android - Json 异常:应为 BEGIN_OBJECT 但为 BEGIN_ARRAY
问题描述
我花了 3 个小时,我找不到解析错误的原因。
我有这个 JSON
[
{
"id": "WMWSW31030T222518",
"modelName": "MINI",
"name": "Vanessa",
"make": "BMW",
"latitude": 48.134557,
"longitude": 11.576921,
"carImageUrl": "https://cdn.sixt.io/codingtask/images/mini.png"
},
{
"id": "WMWSU31070T077232",
"modelName": "MINI",
"name": "Regine",
"make": "BMW",
"latitude": 48.114988,
"longitude": 11.598359,
"carImageUrl": "https://cdn.sixt.io/codingtask/images/mini.png"
}
]
解析后我得到了这个错误
An error happened: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
这是我的代码
--存储库--
interface CarRepository {
suspend fun getCars(): LiveData<Resource<List<Car>>>
}
class CarRepositoryImpl(private val datasource: CarDatasource,
private val dao: CarDao): CarRepository{
override suspend fun getCars(): LiveData<Resource<List<Car>>> {
return object : NetworkBoundResource<List<Car>, ApiResult<Car>>() {
override fun processResponse(response: ApiResult<Car>): List<Car>
= response.items
override suspend fun saveCallResults(items: List<Car>)
= dao.save(items)
override fun shouldFetch(data: List<Car>?): Boolean
= data == null || data.isEmpty()
override suspend fun loadFromDb(): List<Car>
= dao.getCars()
override fun createCallAsync(): Deferred<ApiResult<Car>>
= datasource.fetchCars()
}.build().asLiveData()
}
}
- 汽车服务 -
interface CarService {
@GET("cars")
fun fetchCars(): Deferred<ApiResult<Car>>
}
--ApiResult--
data class ApiResult<T>(val items: List<T>)
--NetworkBoundResource--
abstract class NetworkBoundResource<ResultType, RequestType> {
private val result = MutableLiveData<Resource<ResultType>>()
private val supervisorJob = SupervisorJob()
suspend fun build(): NetworkBoundResource<ResultType, RequestType> {
withContext(Dispatchers.Main) { result.value =
Resource.loading(null)
}
CoroutineScope(coroutineContext).launch(supervisorJob) {
val dbResult = loadFromDb()
if (shouldFetch(dbResult)) {
try {
fetchFromNetwork(dbResult)
} catch (e: Exception) {
Log.e("NetworkBoundResource", "An error happened: $e")
setValue(Resource.error(e, loadFromDb()))
}
} else {
Log.d(NetworkBoundResource::class.java.name, "Return data from local database")
setValue(Resource.success(dbResult))
}
}
return this
}
fun asLiveData() = result as LiveData<Resource<ResultType>>
// ---
private suspend fun fetchFromNetwork(dbResult: ResultType) {
Log.d(NetworkBoundResource::class.java.name, "Fetch data from network")
setValue(Resource.loading(dbResult)) // Dispatch latest value quickly (UX purpose)
val apiResponse = createCallAsync().await()
Log.e(NetworkBoundResource::class.java.name, "Data fetched from network")
saveCallResults(processResponse(apiResponse))
setValue(Resource.success(loadFromDb()))
}
@MainThread
private fun setValue(newValue: Resource<ResultType>) {
Log.d(NetworkBoundResource::class.java.name, "Resource: "+newValue)
if (result.value != newValue) result.postValue(newValue)
}
@WorkerThread
protected abstract fun processResponse(response: RequestType): ResultType
@WorkerThread
protected abstract suspend fun saveCallResults(items: ResultType)
@MainThread
protected abstract fun shouldFetch(data: ResultType?): Boolean
@MainThread
protected abstract suspend fun loadFromDb(): ResultType
@MainThread
protected abstract fun createCallAsync(): Deferred<RequestType>
--资源--
data class Resource<out T>(val status: Status, val data: T?, val error: Throwable?) {
companion object {
fun <T> success(data: T?): Resource<T> {
return Resource(
Status.SUCCESS,
data,
null
)
}
fun <T> error(error: Throwable, data: T?): Resource<T> {
return Resource(
Status.ERROR,
data,
error
)
}
fun <T> loading(data: T?): Resource<T> {
return Resource(
Status.LOADING,
data,
null
)
}
}
enum class Status {
SUCCESS,
ERROR,
LOADING
}
}
谁能告诉我为什么解析器失败了?
解决方案
错误在这里,您应该使用列表而不是 ApiResult,因为 ApiResult 是具有列表的对象,而 GSON 尝试解析对象并查找具有属性名称项的列表。
//change to List<Car>
interface CarService {
@GET("cars")
fun fetchCars(): Deferred<List<Car>>
}
推荐阅读
- python - 如何在多个窗口 Tkinter 程序中保持恒定布局?
- c# - 如何在同一网络之间连接到 UWP 应用
- ios - Xcode 11.3 无法为 iOS 13.3 设置目标,即该选项不存在
- c# - 为什么我的 ADO.NET 查询不是在单次执行中运行,而是在单独执行中运行?
- mysql - 在mysql中保存数千个多个多边形组合的逻辑方法
- kdevelop - 如何在 KDevelop 中禁用变量多色?
- c# - 将 docx 转换为 byte[] 并使用 File.WriteAllBytes 将其保存到磁盘
- xcode - 我的一些图集动画被裁剪了,只显示了一半
- ios - SwiftUI - 具有透明背景的按钮
- java - 按子类型搜索失败