android - 带有协程和流的 Android 通用 Gson.fromJson() 转换
问题描述
我正在制作用于点击 otp api 的通用类。任何人都可以使用 otp 部分只需传递请求、响应类和 url,所有这些都将由这个 otp 部分完成。请注意:此响应类可以是不同的类型(例如:MobileOtpResponse、EmailOtpResponse)
下面是通用 OtpClient,它接受任何请求类型并返回特定传递的 ResponseType(例如:传递的请求类是 OtpRequest,传递的响应类型类是 OtpResponse)
interface OtpClient {
@POST
suspend fun <Request : Any, ResponseType> sendOtp(@Url url: String,
@Body request:@JvmSuppressWildcards Any): @JvmSuppressWildcards ResponseType
}
OTP请求
data class OtpRequest(@SerializedName("mobile_number") val mobileNumber: String,@SerializedName("app_version") val appVersion: String)
响应
data class OtpResponse(@SerializedName("status") val status: String = "",
@SerializedName("response") val response: OtpData? = null)
data class OtpData(
@SerializedName("otp_status") val otpStatus: Boolean = false,
@SerializedName("message") val message: String = "",
@SerializedName("error") val error: Int? = null,
@SerializedName("otp_length") val otpLength: Int? = null,
@SerializedName("retry_left") val retryLeft: Int? = null,)
现在我创建 Repo 来调用这个 api 这只是使用 flow 并且当数据获取时它会发出数据
class OtpRepoImpl<out Client : OtpClient>(val client: Client) :OtpRepo {
override fun <Request:Any, ResponseType> sentOtpApi(url: String, request: Request): Flow<ResponseType> {
return flow<ResponseType> {
// exectute API call and map to UI object
val otpResponse = client.sendOtp<Request, ResponseType>(url,request)
emit(otpResponse)
}.flowOn(Dispatchers.IO) // Use the IO thread for this Flow
}
}
此 repo 用于 viewmodel 类
@ExperimentalCoroutinesApi
fun <A : Class<ResponseType>, Request : Any, ResponseType : Any> sendOtp(a: Class<ResponseType>, request: Request, response: ResponseType, url: String) {
viewModelScope.launch {
repo.sentOtpApi<Request, ResponseType>(url, request = request)
.onStart { _uiState.value = OtpState.Loading(true) }
.catch { cause ->
_uiState.value = OtpState.Loading(false)
getResponseFromError<Class<ResponseType>,ResponseType>(cause, response) {
// emit(it)
}
}
.collect {
_uiState.value = OtpState.Loading(false)
_uiState.value = OtpState.Success(it)
}
}
}
正如你在上面看到的,这个 sendOtp 方法是从视图类调用的,在这个方法中,我们使用 repo.sentOtpApi 并传递通用请求响应类型。我在 catch 块中获取数据,因为 api 是在 400 HttpException 中发送错误 otp 数据,所以我创建了另一个获取错误响应的方法getResponseFromError它应该解析 errorBody 响应并调用此 lambda 块。
private suspend fun <A : Class<*>, ResponseType : Any> getResponseFromError( cause: Throwable, rp: ResponseType, block: suspend (ResponseType) -> Unit) {
if (cause is HttpException) {
val response = cause.response()
if (response?.code() == 400) {
println("fetching error Response")
val errorResponse = response.errorBody()?.charStream()
val turnsType = object : TypeToken<ResponseType>() {}.type
val finalErrorResponse = Gson().fromJson<ResponseType>(errorResponse, turnsType)
block(finalErrorResponse)
} else {
println("someOther exception")
}
} else
_uiState.value = OtpState.Error(cause)
}
所以在这里我面临上述方法中的问题
val turnsType = object : TypeToken<ResponseType>() {}.type
val finalErrorResponse = Gson().fromJson<ResponseType>(errorResponse, turnsType)
block(finalErrorResponse)
这个 finalErrorResponse 正在返回 LinkedTreeMap 而不是ResponseType(在这种情况下是 OtpResponse)我也尝试过像这样使用 Class<*> 类型
val turnsType = object : TypeToken<A>() {}.type
val finalErrorResponse = Gson().fromJson<A>(errorResponse, turnsType)
但它不工作。
这个 sendOtp viewmodel 函数的调用就像
var classType = OtpResponse::class.java
otpViewModel.sendOtp(a = classType, request = otpRequest, response = OtpResponse() , url =
"http://preprod-api.nykaa.com/user/otp/v2/send-wallet-otp")
[![finalErroResponse 中的值][1]][1] [1]: https://i.stack.imgur.com/Holui.png
必需:finalErroResponse 应该是 OtpResponse 类型,因为它是在 sentOtp 函数中传递的
请帮忙 :)
解决方案
推荐阅读
- database - 如何开始开发 AR 并将其与 Cloud/DB 集成?
- csv - 杰克逊CSV反序列化忽略标题顺序
- node.js - 不向数据库发送数据
- openssl - Openssl,验证返回码:20(无法获取本地颁发者证书)
- java - 有什么方法可以在 @Service 上使用 @ControllerAdvice
- ruby-on-rails - 使用 Ruby 进行 PayPal 支付
- python - 从地理数据框导入图形时丢失图形连接
- typescript - 让 VSCode 与 TypeScript 一起工作需要什么配置?
- reactjs - 在 VScode 中使用文档时出错
- javascript - 如何在 litelement 中实现 select2