Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Kotlin.Android. Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

I ran into the same problem today while launching the app.I really appreciate your help in solving my problem.
Api and JSON – https://swapi.dev/api/people/

Below is the error code:

Error

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.skreep.starwarsappandroid, PID: 20521
    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:40)
        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)

This is the code Model

data class Characters(
    @SerializedName("name")
    val characters: String,
    @SerializedName("gender")
    val gender: String
)

This is code model (List Characters)

class CharacterList: ArrayList<Characters>()

This is code my ViewModel

class HomeViewModel() : ViewModel() {

    var repository = StarWarsRepository()
    val list: MutableLiveData<Response<CharacterList>> = MutableLiveData()

    fun getCharacterViewModel() {
        viewModelScope.launch {
            list.value = repository.getCharacters()
        }
    }
}

This is code my interface

@GET("people/")
    suspend fun getCharacters(): Response<CharacterList>

This is code my Fragment

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!
    private lateinit var viewModel: HomeViewModel
    lateinit var recyclerView: RecyclerView
    private lateinit var adapter: HomeListAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        viewModel = ViewModelProvider(this)[(HomeViewModel::class.java)]
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        val view = binding.root

        recyclerView = binding.recycler
        adapter = HomeListAdapter()
        recyclerView.layoutManager= LinearLayoutManager(requireContext())
        recyclerView.adapter = adapter
        getCharacterViewModel()
        return view

    }

    private fun getCharacterViewModel(){

        viewModel.getCharacterViewModel()
        viewModel.list.observe(this, { list ->
            list.body()?.let { adapter.setList(it) }
        })
    }

}

Adapter

package com.skreep.starwarsappandroid.ui.fragments.home.adapter

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.skreep.starwarsappandroid.data.remote.model.Characters
import com.skreep.starwarsappandroid.databinding.ItemCharacterBinding


class HomeListAdapter() :
    RecyclerView.Adapter<HomeListAdapter.HomeViewHolder>() {
    var peopleList = emptyList<Characters>()

    class HomeViewHolder(var binding: ItemCharacterBinding) :
        RecyclerView.ViewHolder(binding.root) {

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeViewHolder {
        return HomeViewHolder(
            ItemCharacterBinding.inflate(
                LayoutInflater
                    .from(parent.context), parent, false
            )
        )
    }

    override fun onBindViewHolder(holder: HomeViewHolder, position: Int) {
        val characterList = peopleList[position]
        holder.binding.characterName.text = characterList.characters
        holder.binding.characterGender.text = characterList.gender
    }

    override fun getItemCount(): Int {
        return peopleList.size
    }

    @SuppressLint("NotifyDataSetChanged")
    fun setList(list: List<Characters>) {
        peopleList = list
        notifyDataSetChanged()
    }


    }

>Solution :

You need to create additional model to parse json into, for example call it CharactersResponse and use it in request function instead of CharacterList. So it will look like the following:

data class CharactersResponse(
    @SerializedName("results")
    val charactersList: CharacterList
)

@GET("people/")
suspend fun getCharacters(): Response<CharactersResponse>

You missed the results object from json representation, where characters are stored:

{
  "count": 82, 
  "next": "https://swapi.dev/api/people/?page=2", 
  "previous": null, 
  "results": [ ...
      
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading