胖蔡说技术
随便扯扯

MVVM之Retrofit与LiveData的集成

引子

对于一个健全的Android应用而言,网络请求部分必不可少,而且可以说是很重要,早些时候对于网络请求这块需要我们程序员所花费的精力不可说少,什么请求参数拼接、请求头、请求方法、请求内容等封装,以及数据model与请求、返回结果之间的格式化转换,一个个都代表着工作量,渐渐的网络请求框架丰富起来了,它做了我们绝大多数工作,像优化网络请求加载速度、请求缓存、注解封装请求等。类似Vollery、OkHttp请求的优化了我们的请求过程、缓存,而最让人欣慰的是Retrofit的出现,Retrofit本身并不处理请求,它做的是请求过程的封装、简化,让我们开发人员不必与过多的关注请求过程,而关注与结果本身。随着RxJava的出现,可以说是Retrofit请求框架迎来了巅峰,RxJava的链式、切换线程和Observer属性与Retrofit简直就是标配,让我们的请求更加简单。MVVM中采用的是LiveData实现的Observer特性,想着与RxJava的observer的功能重合,且ViewModle中本身就是用的LiveData处理,所以就想着直接通过Retrofit将LiveData进行封装替代Rxjava了。
7f5b3cc826e7082

三方地址

集成

Retrofit的封装

Retrofit采用单例模式封装,并设置公用头信息

    /**
      *@Author hfcai https://www.enjoytoday.cn
      *  Retrofit工厂,单例
      */
    class RetrofitFactory private constructor() {

        /*
            单例实现
         */
        companion object {
            val instance: RetrofitFactory by lazy { RetrofitFactory() }
        }

        private val interceptor: Interceptor
        private val retrofit: Retrofit

        //初始化
        init {
            //通用拦截
            interceptor = Interceptor { chain ->
                val request: Request = chain.request()
                    .newBuilder()
                    .addHeader("Content-Type", "application/json")
                    .addHeader("charset", "UTF-8")
                    .build()

                chain.proceed(request)
            }

            //Retrofit实例化
            retrofit = Retrofit.Builder()
                .baseUrl(Common.SERVER_ADDRESS)
                .addConverterFactory(GsonConverterFactory.create()) //设置数据格式化工具
                .addCallAdapterFactory(LiveDataCallAdapterFactory()) //是指代理请求返回处理
                .client(initClient())
                .build()
        }

        /*
            OKHttp创建
         */
        private fun initClient(): OkHttpClient {
            return OkHttpClient.Builder()
                .addInterceptor(initLogInterceptor())
                .addInterceptor(interceptor)
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build()
        }

        /*
            日志拦截器
         */
        private fun initLogInterceptor(): HttpLoggingInterceptor {
            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BODY
            return interceptor
        }

        /*
            具体服务实例化
         */
        fun <T> create(service: Class<T>): T {
            return retrofit.create(service)
        }
    }

其中, addCallAdapterFactory(LiveDataCallAdapterFactory()) 即为LiveData的适配器。

实现LiveData适配器

通过实现Retrofit的CallAdapter适配器来代理请求和处理返回信息,如下:

    /**
     * @ClassName LiveDataCallAdapterFactory
     * @Description LiveData retrofit适配器
     * @Author hfcai https://www.enjoytoday.cn
     * @Date 2019/4/4 16:17
     * @Version 1.0
     */
    class LiveDataCallAdapterFactory : CallAdapter.Factory() {



        /**
         * 实现allAdapter.Factory()的get方法用于返回我们实现的CallAdapter<*>对象
         */
        override fun get(returnType: Type?, annotations: Array<out Annotation>?,
                         retrofit: Retrofit?): CallAdapter<*>? {
            if(returnType !is ParameterizedType){
                throw IllegalArgumentException("返回值需为参数化类型")
            }
            //获取returnType的class类型
            val returnClass = CallAdapter.Factory.getRawType(returnType)
            if(returnClass != RespLiveData::class.java){
                throw IllegalArgumentException("MutableLiveData")
            }
            val type = CallAdapter.Factory.getParameterUpperBound(0, returnType)
            val a = LiveDataCallAdapter(type)
            LogUtils.e("get request data:${a.responseType()}")
            return a
        }
        /**
         * 请求适配器
         *
         * T:需要返回的数据RespLiveData<T>
         * R:
         */
        class LiveDataCallAdapter(/**val map: MutableMap<String,RespLiveData<*>>,**/var type:Type):CallAdapter<RespLiveData<*>>{

            override fun <R>adapt(call: Call<R>?): RespLiveData<*>? {
                var mutableLiveData:RespLiveData<*>? =null
                call?.let {
                    LogUtils.e("开始请求数据")
                    val requestUrl =call.request().url().encodedPath()
                    LogUtils.e("请求url:$requestUrl")
                    mutableLiveData = object : RespLiveData<R>(){
                        override fun onActive() {
                            super.onActive()
                            request(call)
                        }
                    }
                }
                return mutableLiveData
            }


            override fun responseType(): Type = type

        }
    }

如上,返回自定义的LiveDataCallAdapter方法,具体实现放在自定义的RespLiveData里处理

自定义网络请求处理Live

我主要是把处理请求和响应下发放在自定义的LiveData里面做,当然这不是一定的,你也可以直接在LiveDataCallAdapter里匿名实现请求处理。如下为自定义的LiveData:

    
    /***
     * 泛型T需是BaseResp的子类,对应的api也需要是BaseResp的子类
     */
    open class RespLiveData<T>: MutableLiveData<T>() {

        //这个作用是业务在多线程中,业务处理的线程安全问题,确保单一线程作业
         val flag = AtomicBoolean(false)

        /**
         * 请求回调重写
         */
        fun<R> request(callHttp: Call<R>){
            if(flag.compareAndSet(false,true)){
                callHttp.enqueue(object: Callback<R> {
                    override fun onFailure(call: Call<R>?, t: Throwable?) {
                        LogUtils.e("CallAdapter onFailure:${t?.message}")
                        postValue(null)

                    }
                    override fun onResponse(call: Call<R>?, response: Response<R>?) {
                        if (response?.isSuccessful!!) {
                            try {
                                val a = response.body() as T
                                postValue(a)
                            }catch (e: Exception){
                                e.printStackTrace()
                                postValue(null)
                            }
                        }else{
                              postValue(null)
                        }
                    }
                })
            }
        }

    }

创建并使用

    /**
     * @ClassName TestApi
     * @Description api请求创建
     * @Author hfcai
     * @Date 2019/4/4 17:20
     * @Version 1.0
     */

    @TestRemoteApi(apiName = "测试模块")
    interface TestApi{
        /**
         * 获取验证码
         */
        @POST("/api/")
        fun getTest(@Body req: TestReq): RespLiveData<TestResp>
    }



    //使用

    class TestViewModel:ViewModel(){

        fun requestTest(){
          val req = TestReq(10)
          RetrofitFactory.instance.create(TestApi::Class.java)
                          .getTest(req)
                          .observeForever{
                            val resp:TestResp = it
                          }
        }

    }
赞(4) 打赏
转载请附上原文出处链接:胖蔡说技术 » MVVM之Retrofit与LiveData的集成
分享到: 更多 (0)

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏