先看成品使用:

lifecycleScope.launch {
            /**
             * case1:只需要响应正确的结果
             */
            //LoadingDialog.show() 可以很方便的处理LoadingDialog的逻辑
            val result1 = RepoWanAndroid().searchArticle("安卓")
            //LoadingDialog.cancel()

            if (result1.isSuccess) {
                L.err(result1.data?.datas?.get(0)?.title)
            }

            /**
             * case2:需要处理错误
             */
            //LoadingDialog.show()
            val result2 = RepoWanAndroid().searchArticle("安卓")
            //LoadingDialog.cancel()
            if (result1.isSuccess) {
                L.err(result2.data?.datas?.get(0)?.author)
            }else{
                L.err("所有的错误都会走到这里,如果不需区分错误的类型,直接在这里处理错误即可")
                //针对不同类型的错误进行处理
                when (result1.errorType) {
                    BaseBean.ErrorType.NetworkError ->{}
                    BaseBean.ErrorType.ServerError ->{}
                    BaseBean.ErrorType.UnknownError ->{}
                }

                //针对错误码进行处理
                when (result1.errorCode) {
                    404->{}
                    500->{}
                }
            }
        }

协程的出现,让我们可以最大限度的解决掉回调的问题,使代码可以按照线性的思维去编写。

此方案最核心一点,就是在网络数据返回的时候,顺带处理了错误信息,避免使用try catch,也就是底部SuspendCall类里的逻辑。思路很简单,直接上代码吧。

class RepoWanAndroid {
    private val api = ApiServiceManager.getService(ApiWanAndroid::class.java)

    suspend fun searchArticle(keyword: String): BaseBean<ArticleSearchResultBean> {
        //Repository的意义在于可以封装一些默认参数,比如自己第三方接口的key,或者自己uid等
        return api.searchArticle(keyword)
    }
}
interface ApiWanAndroid {

    @POST("article/query/0/json")
    @FormUrlEncoded
    suspend fun searchArticle(@Field("k") keyword: String): BaseBean<ArticleSearchResultBean>

}
class ApiServiceManager private constructor() {
    private val mRetrofit: Retrofit = Retrofit.Builder()
        .client(OkHttpClientManager.getClient())
        //String converter
        //用于直接返回String类型,遇到第一个匹配的Converter将会终止匹配
        .addConverterFactory(ScalarsConverterFactory.create())
        //Json Converter
        //用于返回Bean对象
        .addConverterFactory(MoshiConverterFactory.create())
        //handle returns
        //处理返回结果,
        .addCallAdapterFactory(SuspendCallAdapterFactory.create())
        .baseUrl("https://www.wanandroid.com/")
        .build()

    // 获取对应的Service
    fun <T> create(service: Class<T>?): T {
        return mRetrofit.create(service)
    }

    companion object {
        private fun getInstance(): ApiServiceManager {
            return SingletonHolder.instance
        }

        fun <T> getService(service: Class<T>?): T {
            return getInstance().create(service)
        }
    }

    // 静态内部类 形式的单例
    private object SingletonHolder {
        val instance = ApiServiceManager()
    }

}
class CommonParamsInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()
        val builder: HttpUrl.Builder = request.url.newBuilder()

        //添加公用参数
        builder.addQueryParameter("time", System.currentTimeMillis().toString())
        val newRequest: Request = request.newBuilder()
            .url(builder.build())
            .build()
        L.err("http_data url:${newRequest.url}")
        return chain.proceed(newRequest)
    }
}
class OkHttpClientManager private constructor() {
    private val okHttpClient: OkHttpClient

    // 请求超时时间
    private val DEFAULT_TIMEOUT: Long = 20

    init {
        val loggingInterceptor = HttpLoggingInterceptor { message -> //message是网络返回来的内容
            System.err.println("http_data:${message}")
        }
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)

        //手动创建一个OkHttpClient并设置超时时间
        val httpClientBuilder = OkHttpClient.Builder()
        okHttpClient = httpClientBuilder
            .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .addInterceptor(CommonParamsInterceptor())
            .addInterceptor(loggingInterceptor)
            .build()

    }

    companion object {
        fun getClient(): OkHttpClient {
            return SingletonHolder.instance.okHttpClient
        }
    }


    private object SingletonHolder {
        val instance = OkHttpClientManager()
    }

}

class SuspendCallAdapterFactory : CallAdapter.Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): CallAdapter<*, *>? {

        //第一个泛型就是BaseBean类,这种情况可能是api接口没有声明协程suspend符号,抛出异常提醒
        if (getRawType(returnType) == BaseBean::class.java) {
            throw IllegalArgumentException("Method must be declare suspend, please check function declaration at API interface")
        }

        //协程挂起函数默认返回值是Call<*>,如果不满足该条件,那么返回null让retrofit选择其他家伙来处理
        if (Call::class.java != getRawType(returnType)) {
            return null
        }

        //检查Call内部的泛型是否包含了其他泛型
        check(returnType is ParameterizedType) {
            "return type must be BaseBean<*> or BaseBean<out *> for Call<*> check"
        }

        //获取Call类包裹的第一个泛型
        val responseType = getParameterUpperBound(0, returnType)

        //Call类包裹的第一个泛型不是BaseBean类,那么返回null,让retrofit选择其他 CallAdapter.Factory
        if (getRawType(responseType) != BaseBean::class.java) {
            return null
        }

        //确保BaseBean内部包的泛型其还包裹另外一层泛型,比如 BaseBean<*>
        check(responseType is ParameterizedType) { "return type must be BaseBean<*> or BaseBean<out *> for BaseBean<*> check" }

        //获取BaseBean类包裹的第一个泛型
        val callReturnType = getParameterUpperBound(0, returnType as ParameterizedType)
        return SuspendCallAdapter<Any?>(callReturnType)
    }

    companion object {
        fun create(): SuspendCallAdapterFactory {
            return SuspendCallAdapterFactory()
        }
    }
}
class SuspendCallAdapter<R>(private val responseType: Type) : CallAdapter<R, SuspendCall<R>> {
    /**
     * 真正数据的类型,如Call<T> 中的 T,这个T会作为  Converter.Factory.responseConverter的第一个参数
     *
     * @return
    </T> */
    override fun responseType(): Type {
        return responseType
    }

    override fun adapt(call: Call<R>): SuspendCall<R> {
        return SuspendCall(call)
    }
}

class SuspendCall<R>(var delegate: Call<R>) : Call<Any> {

    override fun execute(): Response<Any> {
        throw UnsupportedOperationException("CustomCall doesn't support execute")
    }


    override fun enqueue(callback: Callback<Any>) {
        delegate.enqueue(object : Callback<R> {
            override fun onResponse(call: Call<R>, response: Response<R>) {
                val baseBean = response.body() as BaseBean<Any>
                if (baseBean.data == null) {
                    onFailure(call, Exception("数据为空"))
                    return
                }
                baseBean.isSuccess = true
                callback.onResponse(this@SuspendCall, Response.success(baseBean))
                return
            }

            override fun onFailure(call: Call<R>, t: Throwable) {
                val baseBean = BaseBean<Any>()
                baseBean.isSuccess = false
                baseBean.errorMsg = t.message
                baseBean.errorCode = -1
                if (t is UnknownHostException) {
                    //可以针对各种情况进行处理
                    baseBean.errorType = BaseBean.ErrorType.ServerError
                }
                callback.onResponse(this@SuspendCall, Response.success(baseBean))
            }
        })
    }

    override fun isExecuted(): Boolean {
        return delegate.isExecuted
    }

    override fun cancel() {
        delegate.cancel()
    }

    override fun isCanceled(): Boolean {
        return delegate.isCanceled
    }

    override fun clone(): Call<Any> {
        return SuspendCall(delegate)
    }

    override fun request(): Request {
        return delegate.request()
    }

    override fun timeout(): Timeout {
        return delegate.timeout()
    }
}

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐