Android网络库隔离框架

1、背景

在平常开发过程当中,网络请求功能是必不可少的,所以从中衍生出了一系列网络加载库,如URLConnection,Volley,OkHttp,Retrofit等。而在项目的开发过程当中,随着需求的改变,咱们使用的网络加载库也可能会随着改变(替换网络加载库)。所以,本章介绍的是如何设计一种网络库隔离的框架,当出现网络加载库替换的状况时,尽量小的改动源代码(即符合开闭原则,扩展是开放的,修改是封闭的)。java

2、设计思路

首先要明白的是,使用网络请求功能的界面入口是很是多的(例如登陆,各类数据获取,文件上传等),所以,第一个须要处理的问题就是,如何避免网络加载库与页面请求直接交互。当出现网络库替换时,大量的直接交互,带来的后果必然是大量的源代码修改,这显示是违法了咱们的开闭原则。android

接着是,如何引入新替换的网络加载库,这至关因而新添加了另一个网络库的各类请求功能。最终的效果就是咱们使用着不一样的网络库来完成相同的功能,既然功能是一致的,那么咱们就须要考虑如何规范他们的功能(函数)定义。git

基于以上两点的考虑,咱们采用代理模式来实现咱们的网络库隔离框架。github

3、设计模式

1.架构图

照片来自网络搜索

2.说明

(1)代理模式:为其余对象提供一种代理以控制对这个对象的访问 (2)Proxy代理类:用来替代实际的网络加载库,避免界面代码与实际的网络加载直接交互 (3)RealSubject:真实请求类,在咱们的案例中,就是一种网络加载库。每添加一种网络请求库,即添加一个对应的真实请求类便可(这里就是根据不一样的网络加载库,实际进行请求功能的地方) (4)Subject:用来规范新添加的各类网络加载库以及代理类的功能使用。为何要规范代理的功能?由于代理类,代理的是真实类的功能行为,所以代理类须要与真实类的功能保持一致。json

4、Kotlin实现

1.Subject

// 代理模式中,用于规范代理类与真实类的功能接口
// 咱们暂且只定义了get和post功能
// ICallBack函数是自定义的请求回调类,后续介绍
interface IHttpProxy {
    fun getHttp(url: String, callback: ICallBack)
    fun postHttp(url: String, params: Map<String, Any>, callback: ICallBack)
}
复制代码

2.Proxy

// object修饰,是一种饿汉式单例模式
object HttpHelper:IHttpProxy {

    // 代理类中,持有真实对象的引用
    private var httpProxyImpl :IHttpProxy? = null

    // 初始化真实代理对象
    fun init(httpImpl:IHttpProxy){
        httpProxyImpl = httpImpl
    }

    override fun getHttp(url: String, callback: ICallBack) {
        // 运行时,调用真实对象方法
        httpProxyImpl!!.getHttp(url,callback)
    }

    override fun postHttp(url: String, params: Map<String, Any>, callback: ICallBack) 
    {
        // 运行时,调用真实对象方法
        httpProxyImpl!!.postHttp(url,params,callback)
    }
}
复制代码

(1)不了解Kotlin语法的,请查看如下相关文章 【Kotlin_第一行代码】 www.jianshu.com/nb/35111692 (2)代理类,实现了上述定义的接口,并实现了对应的功能,而且能够看出,其功能都是直接调用真实类对象对应功能函数 (3)代理类必须持有真实类的引用,不然没法实现对真实类的代理做用 (4)init方法表示的是传入当前须要被代理的真实类对象设计模式

3.RealSubject

// 实现代理模式中的接口
class OkHttpProxyImpl : IHttpProxy {

    // 声名主线程handler
    val handler = Handler(Looper.getMainLooper())

    //实现对应的get功能函数 
    override fun getHttp(url: String, callback: ICallBack) {
        // 建立okHttpClient对象
        val mOkHttpClient = OkHttpClient()
        //建立一个Request
        val request = Request.Builder()
            .url(url)
            .build()
        //new call
        val call = mOkHttpClient.newCall(request)
        //请求加入调度
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                handler.post {
                    callback.onFailure(e.toString())
                }
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    val string = response.body()?.string()
                    handler.post {
                        callback.onSuccess(string!!)
                    }
                } else {
                    handler.post {
                        callback.onFailure(response.message())
                    }
                }
            }
        })
    }

    override fun postHttp(url: String, params: Map<String, Any>, callback: ICallBack) {
    }
}

复制代码

(1)不对OkHttp的使用作介绍 (2)该类是咱们使用OkHttp网络加载库实现的真实类。实现了对应的接口,并在对应的函数上,实现真实的网络请求功能,并利用自定义的回调函数,将结果回调到使用的地方 (3)目前仅实现get函数的逻辑功能,post函数同理。api

4.自定义回调函数(ICallBack,IHttpCallBack)

// 最底层的回调类,String类型,表示网络请求的返回的json,xml的格式文件,即网络请求返回的第一手数据,未进行任何操做的数据
interface ICallBack {
    fun onSuccess(result: String)
    fun onFailure(result: String)
}
复制代码
//基于ICallBack之上,再次封装的抽象回调类,并对泛型进行处理
abstract class IHttpCallBack<T> : ICallBack {
    // 直接实现对应的onSuccess函数,并对json进行解析以及泛型处理
    override fun onSuccess(result: String) {
        val obj = (Gson().fromJson(result, getRealType(this)))
        val realObj: T? = try {
            obj as T
        } catch (e: Exception) {
            null
        }
        onSuccess(realObj!!) // 返回最终以及解析完成的泛型对象
    }
    
    abstract fun onSuccess(result: T)  // 最终解析后的回调函数

    /**
     * 获取泛型的真实对象
     */
    private fun getRealType(any: Any): Class<*> {
        val genType = any.javaClass.genericSuperclass
        val params = (genType as ParameterizedType).actualTypeArguments
        return params[0] as Class<*>
    }

}
复制代码

5.界面请求

// 一个TextView + 一个Button的简单布局
class MainActivity : AppCompatActivity() {

    // wanandroid开放的api,很是感谢鸿洋大神,获取公众号列表
    val URL = "https://wanandroid.com/wxarticle/chapters/json"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
         // button的点击事件
        json_get_btn.setOnClickListener {
            // 这里使用的是代理对象。直接与界面交互的是代理对象,而非具体的网络加载类对象。 
            // Author是自定义的JavaBean,根据对应的json编写便可,不作介绍 
            HttpHelper.getHttp(URL, object : IHttpCallBack<Author>() {
                // 请求成功,返回的是已经通过泛型处理的回调类
                // 由于传入的回调类是IHttpCallBack,不是ICallBack
                override fun onSuccess(result: Author) {
                    // json_result_tv是布局中的TextView,用于显示结果
                    json_result_tv.text = result.getInfo()
                    Toast.makeText(
                        this@MainActivity,
                        "请求成功", Toast.LENGTH_SHORT
                    ).show()
                }
                // 请求失败后的回调类
                override fun onFailure(result: String) {
                    json_result_tv.text = result
                    Toast.makeText(
                        this@MainActivity,
                        "请求失败", Toast.LENGTH_SHORT
                    ).show()
                }
            })
        }
    }
}
复制代码

(1)须要注意,使用代理类前,须要先传入被代理类的对象,该案例是在Application初始化时设置bash

class MyApp :Application() {
    override fun onCreate() {
        super.onCreate()
        HttpHelper.init(OkHttpProxyImpl()) // 设置真实代理对象
    }
}
复制代码

6.替换网络加载库步骤

(1)仿照OkHttpProxyImpl,实现对应网络加载库的真实类,如VolltyProxyImpl。网络

// Volley网络加载库真实请求类
class VolleyProxyImpl :IHttpProxy {
    override fun postHttp(url: String, params: Map<String, Any>, callback: ICallBack) {
        // 具体的volley post请求
    }
    override fun getHttp(url: String, callback: ICallBack) {
        // 具体的volley get请求
    }
}
复制代码

(2)替换代理类中被代理的对象,即修改MyApp中的代码架构

class MyApp :Application() {
    override fun onCreate() {
        super.onCreate()
        HttpHelper.init(VolltyProxyImpl()) // 设置为新网络加载类对象
    }
复制代码

}

7.最后

至此,咱们的网络隔离库框架雏形已搭建完毕,更多的功能请自定扩展。若有任何不正确地方,欢迎批评指正。 很是感谢【腾讯课堂-Android高级开发专题课】

【项目地址】:github.com/y0000c/Http…

相关文章
相关标签/搜索