为 Retrofit Kotlin 协程创建自定义网络监听器

Nik*_*nki 1 android kotlin-coroutines

我正在使用 retofit 服务而不使用回调。所以,它可能与 Kotlin Coroutine 一起使用suspend fun。我参考了很多博客、媒体和教程。scope嗯,使用带有线程的协程很容易获得响应IO and Main

因此,在参考了一些示例之后,我考虑执行如下代码:

改造服务接口RetrofitInterfaces.kt

interface RetrofitInterfaces {
    @FormUrlEncoded
    @POST("get-videos-pagination")
    suspend fun getTemplates(@Field("app_name") app_name: String,
                             @Field("sort_by") sortBy: String,
                             @Field("video_loaded_ids") loadedIds: String): Response<Model_Video_List>
}
Run Code Online (Sandbox Code Playgroud)

其中Model_Video_List.ktclass 是我的响应数据类。

改造建造者RetrofitClient.kt

object RetrofitClient {
    fun makeRetrofitService(mContext: Context): RetrofitInterfaces {
    val gson = GsonBuilder().setLenient().create()
    return Retrofit.Builder()
            .baseUrl(AppPreferences.getBaseUrl(mContext) + "/api/v3/")
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build().create(RetrofitInterfaces::class.java)
}
}
Run Code Online (Sandbox Code Playgroud)

这里我使用Gsontoserialisedeserialise Json data

现在有什么问题以及问题从哪里开始以获得我正在使用的错误响应ResultWrapper.kt

class ResultWrapper {
    enum class ErrorCode {
        NETWORK,// Connection failed or timeout
        SERVER,// Server errors due to maintenance or over request
        INVALID// Response is success but can't serialised with Data Class!
    }

    interface ResponseWrapper {
        suspend fun onSuccess(response: Response<Any>)

        suspend fun onFailure(eCode: ErrorCode)
    }

    private var responseWrapper: ResponseWrapper? = null
        set

    suspend fun enqueue(response: Response<Any>, responseWrapper: ResponseWrapper) {
        this.responseWrapper = responseWrapper
        if (response.isSuccessful) {
            responseWrapper.onSuccess(response)
        } else {
            val errorCode = response.code()
            when (errorCode) {
                in 200..299 -> {
                    responseWrapper.onFailure(ErrorCode.INVALID)
                }
                in 400..499 -> {
                    responseWrapper.onFailure(ErrorCode.NETWORK)
                }
                in 500..599 -> {
                    responseWrapper.onFailure(ErrorCode.SERVER)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

enqueue fun所以,现在我可以从任何地方调用它app,例如:

private fun getVideoList(loadedIds: String, sortBy: String) {
    val service = RetrofitClient.makeRetrofitService(mContext)
    scope.launch {
        val response = service.getTemplates("MyApp", sortBy, loadedIds)
        val resultWrapper = ResultWrapper()
        resultWrapper.enqueue(response, object : ResultWrapper.ResponseWrapper {
            override suspend fun onSuccess(response: Response<Any>) {

            }

            override suspend fun onFailure(eCode: ResultWrapper.ErrorCode) {

            }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

但我要compile error传入responseresultWrapper.enqueue()因为其中ResultWrapper.ResponseWrapper interface有用 . 定义的方法suspend fun onSuccess(response: Response<Any>)。那么,这里就出现了类型转换的问题!

如果 RetrofitCallBack<T>可以处理任何类型Model or Data classes并返回精确类型。像上面的服务需要Model_Video_List类响应,而其他服务需要自己的类,那么该怎么办呢?是否有唯一的方法为每个服务使用单独的功能?或者只能在Java中实现?!

Sau*_*rat 5

T您可以在类中引入泛型参数类型ResultWrapper,因此每当您创建此类的实例时,您都必须指定实际类型来代替T.

将你的更改ResultWrapper为:

class ResultWrapper<T> {
    enum class ErrorCode {
        NETWORK,// Connection failed or timeout
        SERVER,// Server errors due to maintenance or over request
        INVALID// Response is success but can't serialised with Data Class!
    }

    interface ResponseWrapper<T> {
        suspend fun onSuccess(response: Response<T>)

        suspend fun onFailure(eCode: ErrorCode)
    }

    private var responseWrapper: ResponseWrapper<T>? = null
        set

    suspend fun enqueue(response: Response<T>, responseWrapper: ResponseWrapper<T>) {
        this.responseWrapper = responseWrapper
        if (response.isSuccessful) {
            responseWrapper.onSuccess(response)
        } else {
            val errorCode = response.code()
            when (errorCode) {
                in 200..299 -> {
                    responseWrapper.onFailure(ErrorCode.INVALID)
                }
                in 400..499 -> {
                    responseWrapper.onFailure(ErrorCode.NETWORK)
                }
                in 500..599 -> {
                    responseWrapper.onFailure(ErrorCode.SERVER)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并且还将您的方法更改为:

private fun getVideoList(loadedIds: String, sortBy: String) {
    val service = RetrofitClient.makeRetrofitService(mContext)
    scope.launch {
        val response = service.getTemplates("MyApp", sortBy, loadedIds)
        val resultWrapper = ResultWrapper<Model_Video_List>()
        resultWrapper.enqueue(response, object : ResultWrapper.ResponseWrapper<Model_Video_List> {
            override suspend fun onSuccess(response: Response<Model_Video_List>) {

            }

            override suspend fun onFailure(eCode: ResultWrapper.ErrorCode) {

            }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)