美文网首页
Android Kotlin 可替换的网络隔离库的实现

Android Kotlin 可替换的网络隔离库的实现

作者: 水天滑稽天照八野滑稽石 | 来源:发表于2019-03-02 16:24 被阅读0次

前言

在我们的日常开发中,不可避免的会使用到网络请求,而网络请求库多种多样,如OKHTTP、volley、rxjava+retrofit等等,我们只会用到其中一种,但业务需求改变时,比如之前用的是volley,现在要改成OKHTTP,总不能每个网络请求都要重写吧,直接原地爆炸了,所以需要一个网络隔离库来实现这个需求。

动态代理


举个例子,假设这是一个买卖房的需求:

  • 房产公司是卖房的人
  • 有房的人买房回去房产公司登记自己的房子
  • 客户买房需要去房产公司
  • 业务员持有房子信息,代理房产公司去卖房

这样实际的业务行为就是客户买房就去找业务员
客户需要买什么样的房(用什么的样网络请求库),直接去找业务员就行了,业务员会搞定好一切的
这就是代理模式


Client就相当于客户,Subject就是房产公司,Proxy就是业务员,RealSubject就是我们的有房的人,RealSubject会向Subject提供一个真实的需求,就是卖房

正文

首先我们需要一个房产公司,也就是抽象主题类Subject(网络抽象层接口),房产公司有什么功能先给他列出来(网络请求库有什么功能)

IHttpProcessor

这就是房产公司
现在只有一个查房的功能(post请求)

interface IHttpProcessor {
    //网络访问 post get del update put ...
    fun post(url: String,params: Map<String,Any>,callback: ICallBack)
}

一般网络请求需要url,传递的参数(键值对),还有一个回调

ICallBack

interface ICallBack {
    fun onSuccess(result: String)
    fun onFailure(e: String)
}

HttpCallback

  • ICallBack回调接口的实现
  • 调用者传入的数据类型是未知的,通过泛型接受,反射获取到对应的类型
  • 对返回JSON格式数据进行处理
abstract class HttpCallback<Result> : ICallBack{

    override fun onSuccess(result: String) {
        var gson = Gson()
        //clz为用户输入的类型,如该类是String类,就返回String类
        var clz: Class<*> = analysisClassInfo(this)
        var objResult: Result = gson.fromJson(result,clz) as Result
        //将处理的结果返回调用者
        onSuccess(objResult)
    }

    override fun onFailure(e: String) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
    
    abstract fun onSuccess(result: Result)

    companion object {
        private fun analysisClassInfo(any: Any): Class<*>{
            //getGenericSuperclass()可以得到该类包含的原始类型,参数化类型,数组类型,类型变量,基本数据类型
            var getType: Type = any.javaClass.genericSuperclass
            //获取Result的参数化类型
            var params: Array<Type> = (getType as ParameterizedType).actualTypeArguments
            return params[0] as Class<*>
        }
    }
}

HttpHelper

公司有了,这时候就需要一个业务员了(代理类)
通过上面的代理图可以发现,有房的人的信息是被房产公司持有的
而业务员持有房产公司持有的有房的人的信息
所以业务员持有有房子的人的引用

class HttpHelper : IHttpProcessor {

    override fun post(url: String, params: Map<String, Any>, callback: ICallBack) {
        //业务员找到有房子的人
        mIHttpProcessor!!.post(url, params, callback)
    }

    companion object {
        //有房子的人(持有具体那套网络请求库的引用)
        private var mIHttpProcessor: IHttpProcessor? = null

        fun init(httpProcessor: IHttpProcessor){
            mIHttpProcessor = httpProcessor
        }

        //单例模式
        private var instance: HttpHelper? = null
       @Synchronized fun getInstance():HttpHelper?{
           if (instance == null){
               instance = HttpHelper()
           }
           return instance
       }
    }
}

VolleyProcessor

具体的网络请求库实现(Volley的标准用法)

class VolleyProcessor constructor(var context: Context): IHttpProcessor{

    init {
        mQueue = Volley.newRequestQueue(context)
    }

    companion object {
        private var mQueue: RequestQueue? = null
    }
    
    override fun post(url: String, params: Map<String, Any>,callback: ICallBack) {
        var stringRequest = StringRequest(Request.Method.POST, url,
                Response.Listener { callback.onSuccess(it) },
                Response.ErrorListener { callback.onFailure(it.toString()) })
        mQueue!!.add(stringRequest)
    }

}

用MOCKY模拟一个接口来请求数据

点击进入Mocky


这里MOCK的接口不需要传参数,参数为空

通用的框架初始化

标准写法,新建个App类,继承Application,在Mainfest清单文件声明一下配置

class App : Application() {

    override fun onCreate() {
        super.onCreate()
        //初始化网络选择框架
        HttpHelper.init(VolleyProcessor(this))
    }
}

具体使用

ResponeseData是对应的Bean,这里就不贴出来了

class MainActivity : AppCompatActivity() {

    var url = "http://www.mocky.io/v2/5c7a18b74900007e00a5a695"
    var params: HashMap<String,Any> = HashMap()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
       //hello world 这个TextView弄了个点击事件
        text.setOnClickListener {
            HttpHelper.getInstance()!!.post(url,params,object : HttpCallback<ResponseData>(){
                override fun onSuccess(result: ResponseData) {
                    Toast.makeText(application,result.hello,Toast.LENGTH_LONG).show()
                }
            })
        }
    }
}

红色划线部分传入的数据类型是什么,蓝色划线部分生产的数据类型就是什么,这是HttpCallbcak通过java的反射实现了,并定义了抽象类,让具体的业务实现交付到实际使用时再实现,这里只实现了onSuccess,onFailure同理


效果验证

如果成功,应该会弹出个吐司显示world


可以看到这是成功的
那么我们不用Volley进行网络请求呢?
改成OKHttp要怎么操作?

改用OKHttp进行同样网络请求

和VolleyProcess一样,实现来自IhttpProcessor的接口即可,再通过HttpHelper来代理使用OKHttp进行网络请求

class OKHttpPrpcessor : IHttpProcessor{

    private var mOkHttpClient: OkHttpClient? = null
    private var myHandler: Handler? = null

    init {
        mOkHttpClient = OkHttpClient()
        myHandler = Handler()
    }

    override fun post(url: String, params: Map<String, Any>, callback: ICallBack) {
        var request: Request = Request.Builder().url(url).build()
        mOkHttpClient!!.newCall(request).enqueue(object : Callback{
            override fun onFailure(call: Call?, e: IOException?) {
                callback.onFailure(e.toString())
            }

            override fun onResponse(call: Call?, response: Response?) {
                if (response!!.isSuccessful){
                    val result: String = response.body().string()
                    myHandler!!.post {
                        callback.onSuccess(result)
                    }
                }
            }

        })
    }
}

在.App里切换网络请求框架

class App : Application() {

    override fun onCreate() {
        super.onCreate()
        //初始化网络选择框架
        //HttpHelper.init(VolleyProcessor(this))
        HttpHelper.init(OKHttpPrpcessor())
    }
}

见证奇迹


可以看到效果一模一样,只需通过一行代码就能进行网络请求库的切换!
同理,这种写法适用于切换不同的图片加载框架等等

项目源码

相关文章

网友评论

      本文标题:Android Kotlin 可替换的网络隔离库的实现

      本文链接:https://www.haomeiwen.com/subject/ecajuqtx.html