Android 通用 Gson.fromJson() 转换与协程和流程

问题描述

我正在制作用于访问 otp api 的通用类。任何人都可以使用 otp 部分,只需要传递请求、响应类和 url,所有这些都将由这个 otp 部分完成。 请注意:这个响应类可以是不同的类型(例如:MobileOtpResponse,EmailOtpResponse)

下面是通用的 OtpClient,它接受任何请求类型并返回特定传递的 ResponseType(例如:传递的请求类是 OtpRequest ,传递的 ResponseType 类是 OtpResponse)

 interface OtpClient {
  @POST
  suspend fun <Request : Any,ResponseType> sendOtp(@Url url: String,@Body request:@JvmSuppressWildcards Any): @JvmSuppressWildcards ResponseType
 }

OtpRequest

data class OtpRequest(@Serializedname("mobile_number") val mobileNumber: String,@Serializedname("app_version") val appVersion: String)

OtpResponse

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 这只是使用流,当数据获取时它发出数据


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,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)

但它不起作用。

调用这个 sentOtp 视图模型函数就像

   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 func 中传递的

请帮忙:)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)