I am trying to parse JSON (https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json) to show data in RecyclerView, but I get an error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 13534
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
I see that the problem is that JSON contains just 1 object (pokemon) and inside this object there is array of different pokemons. I don't know how to parse array inside the upper level object in JSON. What should I change to make it work? I suppose that I should save this pokemon object and then parse it but I don't know hot to get inside it. Thanks.
API interface:
interface SimpleApi {
@GET("pokedex.json")
suspend fun getCustomPosts(): Response<List<Post>>
}
Repository:
class Repository {
suspend fun getCustomPosts(): Response<List<Post>>{
return RetrofitInstance.api.getCustomPosts()
}
}
ViewModel:
class MainViewModel(val repository: Repository) : ViewModel() {
val myCustomPosts = MutableLiveData<Response<List<Post>>>()
fun getCustomPosts() {
viewModelScope.launch {
val response: Response<List<Post>> = repository.getCustomPosts()
myCustomPosts.value = response
}
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
private lateinit var binding: ActivityMainBinding
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: MyAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
setRecyclerView()
val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)
viewModel.getCustomPosts()
viewModel.myCustomPosts.observe(this, Observer { response ->
if (response.isSuccessful) {
response.body()?.let { adapter.setData(it) }
} else {
Toast.makeText(this, response.code(), Toast.LENGTH_SHORT).show()
}
})
}
private fun setRecyclerView() {
adapter = MyAdapter()
recyclerView = binding.recyclerView
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
}
}
RecyclerView Adapter:
class MyAdapter() : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private var postList = emptyList<Post>()
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val idView: TextView = view.findViewById(R.id.id_txt)
val nameView: TextView = view.findViewById(R.id.name_txt)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = postList[position]
holder.idView.text = currentItem.id.toString()
holder.nameView.text = currentItem.name
}
override fun getItemCount(): Int = postList.size
fun setData(newList: List<Post>){
postList = newList
notifyDataSetChanged()
}
}
Post:
data class Post(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val name: String
)
CodePudding user response:
Try to use next class in response object:
data class PokedexResponse (
@SerializedName("pokemon")
val pokemons: List<Post>
)
interface SimpleApi {
@GET("pokedex.json")
suspend fun getCustomPosts(): Response<PokedexResponse>
}
My guess is that you missed to parse pokemon
object:
{
"pokemon": [{ ... }]
}