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

Time:02-10

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

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()
    }


    }

CodePudding user response:

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": [ ...
      
  •  Tags:  
  • Related