Ошибка модернизации: - Ожидался BEGIN_ARRAY, но был BEGIN_OBJECT на пути $ - PullRequest
0 голосов
/ 10 июля 2020

Я пытаюсь получить несколько строк из API с помощью Retrofit и Moshi, но сталкиваюсь с этой ошибкой:

Retrofit error:- Expected BEGIN_ARRAY but was BEGIN_OBJECT at path$

Конечная точка API, из которой я запрашиваю данные: https://thecodecafe.in/gogrocer-ver2.0/api/top_selling

Это код настройки для Retrofit и Moshi, который я использую для запроса данных из API:

import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET

private const val BASE_URL = "https://thecodecafe.in/gogrocer-ver2.0/api/"

val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .baseUrl(BASE_URL)
    .build()

interface GroceryApiServices {
    @GET("top_selling")
    fun getProperties():
            Call<List<GroceryProperty>>
}

object GroceryApi {
    val retrofitServices: GroceryApiServices by lazy { retrofit.create(GroceryApiServices::class.java)}
}

Это logi c моей модели представления класс, показывающий, как я хочу получить данные:

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.kotlin_developer.grocerysell.network.GroceryApi
import com.kotlin_developer.grocerysell.network.GroceryProperty
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response


class OverviewViewModel: ViewModel() {

    private val _response = MutableLiveData<String>()
    val response: LiveData<String>
        get() = _response

    init {
        getGroceryProperties()
    }

    private fun getGroceryProperties(){
        GroceryApi.retrofitServices.getProperties().enqueue(object : Callback<List<GroceryProperty>>{
            override fun onFailure(call: Call<List<GroceryProperty>>, t: Throwable) {
                _response.value = t.message
            }

            override fun onResponse(
                call: Call<List<GroceryProperty>>,
                response: Response<List<GroceryProperty>>
            ) {
                _response.value="Success ${response.body()?.size} Grocery Property arrived"
            }

        })
    }

    override fun onCleared() {
        super.onCleared()
    }
}

Ответы [ 2 ]

1 голос
/ 10 июля 2020

Вы получаете сообщение об ошибке: Moshi сообщает, что ожидает массив JSON, но у него есть объект. Ваш метод конечной точки Retrofit выглядит так:

@GET("top_selling")
fun getProperties():
        Call<List<GroceryProperty>>

Здесь вы сообщаете Retrofit, что ожидаете List. В JSON это будет массив, ожидаемый Моши. Однако при нажатии на ссылку на предоставленную вами конечную точку JSON, который вы получаете, будет выглядеть так:

{
  "status": "1",
  "message": "top selling products",
  "data": [
    ...
  ]
}

Как видите, этот JSON не массив, а объект, который содержит массив, и отсюда и возникает ошибка Моши. Чтобы десериализовать его в List, он ожидал начало массива ([), но то, что он обнаружил, было фактически началом объекта ({)

Подводя итог, вы ожидают не List, а объект, который, в свою очередь, содержит этот List (массив data в JSON).

Вам нужно будет определить другой класс, который инкапсулирует этот список , что-то вроде этого:

data class TopSellingResponse(
    val status: String,
    val message: String,
    val data: List<GroceryProperty>
)

Если вы затем измените подпись вашего метода на

@GET("top_selling")
fun getProperties():
        Call<TopSellingResponse>

Moshi должен иметь возможность десериализовать объект JSON в ваш класс и data массив в List, как вы изначально ожидали.

0 голосов
/ 10 июля 2020

Вот как я хочу получить данные в моем классе модели представления

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.kotlin_developer.grocerysell.network.GroceryApi
import com.kotlin_developer.grocerysell.network.GroceryProperty
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response


class OverviewViewModel: ViewModel() {

    private val _response = MutableLiveData<String>()
    val response: LiveData<String>
        get() = _response

    init {
        getGroceryProperties()
    }

    private fun getGroceryProperties(){
        GroceryApi.retrofitServices.getProperties().enqueue(object : Callback<List<GroceryProperty>>{
            override fun onFailure(call: Call<List<GroceryProperty>>, t: Throwable) {
                _response.value = t.message
            }

            override fun onResponse(
                call: Call<List<GroceryProperty>>,
                response: Response<List<GroceryProperty>>
            ) {
                _response.value="Success ${response.body()?.size} Grocery Property arrived"
            }

        })
    }

    override fun onCleared() {
        super.onCleared()
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...