【问题标题】:Creating custom network listner for Retrofit Kotlin Coroutine为 Retrofit Kotlin Coroutine 创建自定义网络监听器
【发布时间】:2020-04-28 06:06:54
【问题描述】:

我正在使用改装服务而不使用回调。因此,它可能与 Kotlin Coroutine suspend fun 一起使用。我参考了许多博客、媒体和许多教程。好吧,使用协程 scopeIO 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>
}

Model_Video_List.kt class 是我的响应数据类。

改造建造师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)
}
}

这里我使用Gsonserialisedeserialise 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)
                }
            }
        }
    }
}

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

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

            }
        })
    }
}

但是我得到了compile error,因为在resultWrapper.enqueue() 中传递了response,因为在ResultWrapper.ResponseWrapper interface 中有用suspend fun onSuccess(response: Response&lt;Any&gt;) 定义的方法。所以,这里就出现了类型转换问题!

如果 Retrofit CallBack&lt;T&gt; 可以处理任何类型的 Model or Data classes 并返回精确的类型。像上面的服务需要Model_Video_List类作为响应,而其他服务需要有自己的,那么该怎么办呢?是否只有一种方法可以为每个服务使用单独的功能?还是只有在 Java 中才有可能?!

【问题讨论】:

    标签: android kotlin-coroutines


    【解决方案1】:

    您可以在您的类ResultWrapper 中引入一个泛型参数类型T,因此每当您创建此类的实例时,您必须指定一个实际类型来代替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)
                    }
                }
            }
        }
    }
    

    并将您的方法更改为:

    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) {
    
                }
            })
        }
    }
    

    【讨论】:

    • 谢谢兄弟!我无法想象在 kotlin 中也完成了这种类型的工作:)
    猜你喜欢
    • 2020-01-16
    • 1970-01-01
    • 2011-10-19
    • 2011-10-19
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 2014-08-22
    相关资源
    最近更新 更多