Android网络库隔离框架

一、背景

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

二、设计思路

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

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

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

三、设计模式

1.架构图
照片来自网络搜索
2.说明

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

四、Kotlin实现

1.Subject
// 代理模式中,用于规范代理类与真实类的功能接口
// 我们暂且只定义了get和post功能
// ICallBack函数是自定义的请求回调类,后续介绍
interface IHttpProxy {
    fun getHttp(url: String, callback: ICallBack)
    fun postHttp(url: String, params: Map, 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, callback: ICallBack) 
    {
        // 运行时,调用真实对象方法
        httpProxyImpl!!.postHttp(url,params,callback)
    }
}

(1)不了解Kotlin语法的,请查看以下相关文章
【Kotlin_第一行代码】 https://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, callback: ICallBack) {
    }
}

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

4.自定义回调函数(ICallBack,IHttpCallBack)
// 最底层的回调类,String类型,表示网络请求的返回的json,xml的格式文件,即网络请求返回的第一手数据,未进行任何操作的数据
interface ICallBack {
    fun onSuccess(result: String)
    fun onFailure(result: String)
}
//基于ICallBack之上,再次封装的抽象回调类,并对泛型进行处理
abstract class IHttpCallBack : 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() {
                // 请求成功,返回的是已经经过泛型处理的回调类
                // 因为传入的回调类是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初始化时设置

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, 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高级开发专题课】

【项目地址】:https://github.com/y0000c/HttpProxyMode

你可能感兴趣的:(Android网络库隔离框架)