Android Retrofit2:在没有 GSON 或 JSONObject 的情况下序列化 null
Posted
技术标签:
【中文标题】Android Retrofit2:在没有 GSON 或 JSONObject 的情况下序列化 null【英文标题】:Android Retrofit2: Serialize null without GSON or JSONObject 【发布时间】:2021-12-27 16:09:19 【问题描述】:我的 android 应用程序中 API 调用的结果可以是一个带有配置的 JSON,它映射到 SupportConfigurationJson
类,或者只是纯 null
。当我得到一个 JSON 时,应用程序可以正常工作,但是当我得到 null
时,我得到了这个异常:
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the object '', but had 'EOF' instead
JSON input: null
我应该避免在这个项目中使用GSON
。我还找到了一个解决方案,API 接口将返回Response<JSONObject>
,之后我的存储库应检查此JSONObject
是否为空,如果不是,则将其映射到SupportConfigurationJson
。但是在项目中,我们总是使用自定义类的响应,所以我想知道,有没有其他解决方案可以使用 null 或自定义数据类获得响应?
GettSupportConfiguration 用例类:
class GetSupportConfiguration @Inject constructor(
private val supportConfigurationRepository: SupportConfigurationRepository
)
suspend operator fun invoke(): Result<SupportConfiguration?>
return try
success(supportConfigurationRepository.getSupportConfiguration())
catch (e: Exception)
/*
THIS SOLUTION WORKED, BUT I DON'T THINK IT IS THE BEST WAY TO SOLVE THE PROBLEM
if (e.message?.contains("JSON input: null") == true)
success(null)
else
failure(e)
*/
//I WAS USING THROW HERE TO SEE WHY THE APP ISN'T WORKING PROPERLY
//throw(e)
failure(e)
SupportConfigurationJson 类:
@Serializable
data class SupportConfigurationJson(
@SerialName("image_url")
val imageUrl: String,
@SerialName("description")
val description: String,
@SerialName("phone_number")
val phoneNumber: String?,
@SerialName("email")
val email: String?
)
SupportConfigurationRepository 类:
@Singleton
class SupportConfigurationRepository @Inject constructor(
private val api: SupportConfigurationApi,
private val jsonMapper: SupportConfigurationJsonMapper
)
suspend fun getSupportConfiguration(): SupportConfiguration? =
mapJsonToSupportConfiguration(api.getSupportConfiguration().extractOrThrow())
private suspend fun mapJsonToSupportConfiguration(
supportConfiguration: SupportConfigurationJson?
) = withContext(Dispatchers.Default)
jsonMapper.mapToSupportSettings(supportConfiguration)
fun <T> Response<T?>.extractOrThrow(): T?
val body = body()
return if (isSuccessful) body else throw error()
fun <T> Response<T>.error(): Throwable
val statusCode = HttpStatusCode.from(code())
val errorBody = errorBody()?.string()
val cause = RuntimeException(errorBody ?: "Unknown error.")
return when
statusCode.isClientError -> ClientError(statusCode, errorBody, cause)
statusCode.isServerError -> ServerError(statusCode, errorBody, cause)
else -> ResponseError(statusCode, errorBody, cause)
SupportConfigurationApi 类:
interface SupportConfigurationApi
@GET("/mobile_api/v1/support/configuration")
suspend fun getSupportConfiguration(): Response<SupportConfigurationJson?>
SupportConfigurationJsonMapper 类:
class SupportConfigurationJsonMapper @Inject constructor()
fun mapToSupportSettings(json: SupportConfigurationJson?): SupportConfiguration?
return if (json != null)
SupportConfiguration(
email = json.email,
phoneNumber = json.phoneNumber,
description = json.description,
imageUrl = Uri.parse(json.imageUrl)
)
else null
我这样创建改造:
@Provides
@AuthorizedRetrofit
fun provideAuthorizedRetrofit(
@AuthorizedClient client: OkHttpClient,
@BaseUrl baseUrl: String,
converterFactory: Converter.Factory
): Retrofit
return Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(converterFactory)
.build()
@Provides
@ExperimentalSerializationApi
fun provideConverterFactory(json: Json): Converter.Factory
val mediaType = "application/json".toMediaType()
return json.asConverterFactory(mediaType)
【问题讨论】:
【参考方案1】:一切都解释了here(1分钟阅读) Api 应该为 null 返回 "",如果您无法更改 API,请将此转换器添加到 Retrofit
【讨论】:
那行得通。非常感谢您分享此资源!【参考方案2】:您正在与您的存储库直接交互,我建议使用
用例
与数据层交互。 因为您没有在此处捕获此异常,所以您的应用正在崩溃
suspend fun getSupportConfiguration(): SupportConfiguration? =
mapJsonToSupportConfiguration(api.getSupportConfiguration().extractOrThrow())
Usecase 通常会捕获这些错误并在 ui 中显示有用的错误消息。
【讨论】:
是的,我在这个类中使用用例并捕获错误,但是序列化过程没有任何重要的逻辑......但是如果有疑问,我也会将其添加到描述中.以上是关于Android Retrofit2:在没有 GSON 或 JSONObject 的情况下序列化 null的主要内容,如果未能解决你的问题,请参考以下文章
Android RxJava2+Retrofit2单文件下载监听进度封装
Android 使用Retrofit2.0+OkHttp3.0实现缓存处理+Cookie持久化第三方库