调用Google Books API遇kotlinx.serialization解码错误求助
问题:Google Books API数据解析失败(Kotlinx Serialization)
调用Google Books API的https://www.googleapis.com/books/v1/volumes/?q=jazz+history接口获取爵士历史相关书籍数据,该接口返回包含kind、totalItems和items数组的JSON结构。但在Android项目中使用kotlinx.serialization解析时触发致命异常,已用Python的json库验证API响应是合法JSON,但Android端解析失败。
错误日志
FATAL EXCEPTION: main Process: com.example.bookshelf, PID: 7875 kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the array '[', but had 'EOF' instead at path: $ JSON input: .....\", \"quoteSharingAllowed\": false } } ] }
相关代码
BookshelfApiService.kt
package com.example.bookshelf.network import retrofit2.http.GET import retrofit2.http.Path interface BookshelfApiService { @GET("?q=jazz+history") suspend fun getBooks(): List<BookshelfBook> @GET("{volume_id}") suspend fun getVolume(@Path("id") id: String): BookshelfVolume }
BookshelfBook.kt
package com.example.bookshelf.network import kotlinx.serialization.Serializable @Serializable data class BookshelfBook( val id: String )
BookshelfVolume.kt
package com.example.bookshelf.network import kotlinx.serialization.Serializable @Serializable data class BookshelfVolume( val imageLinks: Map<String, String> )
BookshelfRepository.kt
package com.example.bookshelf.data import com.example.bookshelf.network.BookshelfApiService import com.example.bookshelf.network.BookshelfBook import com.example.bookshelf.network.BookshelfVolume interface BookshelfRepository { suspend fun getBookshelfBooks(): List<BookshelfBook> suspend fun getBookshelfVolume(id: String): BookshelfVolume } class NetworkBookshelfRepository( private val bookshelfApiService: BookshelfApiService ) : BookshelfRepository { override suspend fun getBookshelfBooks(): List<BookshelfBook> = bookshelfApiService.getBooks() override suspend fun getBookshelfVolume(id: String): BookshelfVolume = bookshelfApiService.getVolume(id) }
BookshelfViewModel.kt
package com.example.bookshelf.ui.model import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY import androidx.lifecycle.viewmodelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.example.bookshelf.BookshelfApplication import com.example.bookshelf.data.BookshelfRepository import com.example.bookshelf.network.BookshelfVolume import kotlinx.coroutines.launch import java.io.IOException sealed interface BookshelfUiState { data class Success(val volumes: List<BookshelfVolume>): BookshelfUiState object Loading: BookshelfUiState object Error: BookshelfUiState } class BookshelfViewModel( private val bookshelfRepository: BookshelfRepository ) : ViewModel() { var bookshelfUiState: BookshelfUiState by mutableStateOf(BookshelfUiState.Loading) private set init { getBookshelfVolumes() } fun getBookshelfVolumes() { viewModelScope.launch { bookshelfUiState = try { val books = bookshelfRepository.getBookshelfBooks().map { it.id } val volumes = books.map { id -> bookshelfRepository.getBookshelfVolume(id) } BookshelfUiState.Success(volumes) } catch (e: IOException) { BookshelfUiState.Error } } } companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { val application = (this[APPLICATION_KEY] as BookshelfApplication) val bookshelfRepository = application.container.bookshelfRepository BookshelfViewModel(bookshelfRepository = bookshelfRepository) } } } }
AppContainer.kt
package com.example.bookshelf.data import com.example.bookshelf.network.BookshelfApiService import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json import okhttp3.MediaType.Companion.toMediaType import retrofit2.Retrofit interface AppContainer { val bookshelfRepository: BookshelfRepository } class DefaultAppContainer : AppContainer { private val baseUrl = "https://www.googleapis.com/books/v1/volumes/" private val retrofit = Retrofit.Builder() .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) .baseUrl(baseUrl) .build() private val retrofitService: BookshelfApiService by lazy { retrofit.create(BookshelfApiService::class.java) } override val bookshelfRepository: BookshelfRepository by lazy { NetworkBookshelfRepository(retrofitService) } }
疑问
- 如何更好地调试该问题?
- 错误是否由Google API返回的数据导致,还是我代码中存在遗漏?
内容的提问来源于stack exchange,提问作者Alexandru Gheorghe
相关产品推荐
相关产品推荐

