I am trying to get data to my app using retrofit, the data is being logged, it however doesn't display. I keep getting this error
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
Not sure what am doing wrong.
The response looks something similar to this
{
info: {
count: 493,
pages: 25
},
results: [
{
id: 1,
name: "Rick Sanchez",
status: "Alive",
species: "Human",
gender: "Male",
image: "https://rickandmortyapi.com/api/character/avatar/1.jpeg",
},
// more characters
]
}
My data class looks like this
data class Character(
@SerializedName("results")
val results: List<Results>,
@SerializedName("info")
val info: List<Info>
)
data class Results(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val name: String,
//
)
This is how my adapter looks like
class CharacterAdapter(var characters: ArrayList<Character>): RecyclerView.Adapter<CharacterAdapter.CharacterViewHolder>() {
fun updateCharacters(newCharacters: List<Character>) {
characters.clear()
characters.addAll(newCharacters)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = CharacterViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.character_item, parent, false)
)
override fun getItemCount() = characters.size
override fun onBindViewHolder(holder: CharacterViewHolder, position: Int) {
holder.bind(characters[position])
}
class CharacterViewHolder(view: View): RecyclerView.ViewHolder(view){
private val characterName = view.characterName
private val progressDrawable = getProgressDrawable(view.context)
fun bind(character:Character){
characterName.text = character.results[adapterPosition].name
}
}
}
My ViewModel
class CharacterViewModel: ViewModel() {
@Inject
lateinit var charactersService: CharactersService
init {
DaggerApiComponent.create().inject(this)
}
private val disposable = CompositeDisposable()
val characters = MutableLiveData<List<Character>>()
val charactersLoadError = MutableLiveData<Boolean>()
val loading = MutableLiveData<Boolean>()
fun refresh(){
fetchCharacters()
}
private fun fetchCharacters(){
loading.value = true
disposable.add(
charactersService.getCharacters()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableSingleObserver<List<Character>>(){
override fun onSuccess(value: List<Character>?) {
characters.value = value
charactersLoadError.value = false
loading.value = false
}
override fun onError(e: Throwable?) {
//
Log.e(TAG, "${e?.message}")
}
})
)
}
override fun onCleared() {
//
}
}
My Activity
class MainActivity : AppCompatActivity() {
lateinit var viewModel: CharacterViewModel
private val characterAdapter = CharacterAdapter(arrayListOf())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(CharacterViewModel::class.java)
viewModel.refresh()
charactersList.apply {
layoutManager = LinearLayoutManager(context)
adapter = characterAdapter
}
swipeRefresh.setOnRefreshListener {
swipeRefresh.isRefreshing = false
viewModel.refresh()
}
observeViewModel()
}
private fun observeViewModel(){
viewModel.characters.observe(this, Observer { characters ->
characters?.let{
charactersList.visibility = View.VISIBLE
characterAdapter.updateCharacters(it)
}
})
viewModel.charactersLoadError.observe(this, Observer { isError ->
})
viewModel.loading.observe(this, Observer { isLoading ->
isLoading?.let{ loadingView.visibility = if(it) View.VISIBLE else View.GONE
if(it) {
charactersList.visibility = View.GONE
}
}
})
}
}
You specify info as a list but the object is expected. You can fix your crash by changing type of the property:
@SerializedName("info")
val info: Info
And I suppose you return List from your service, but there is an object in Json:
CharactersService.getCharacters(): Character