1

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
)
1
  • Could you please add Post class Commented Feb 10, 2022 at 21:47

1 Answer 1

1

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": [{ ... }]
}
Sign up to request clarification or add additional context in comments.

1 Comment

Wow, it works properly! Couldn't think of two classes! Спасибо большое!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.