在平常开发过程当中,网络请求功能是必不可少的,所以从中衍生出了一系列网络加载库,如URLConnection,Volley,OkHttp,Retrofit等。而在项目的开发过程当中,随着需求的改变,咱们使用的网络加载库也可能会随着改变(替换网络加载库)。所以,本章介绍的是如何设计一种网络库隔离的框架,当出现网络加载库替换的状况时,尽量小的改动源代码(即符合开闭原则,扩展是开放的,修改是封闭的)。java
首先要明白的是,使用网络请求功能的界面入口是很是多的(例如登陆,各类数据获取,文件上传等),所以,第一个须要处理的问题就是,如何避免网络加载库与页面请求直接交互。当出现网络库替换时,大量的直接交互,带来的后果必然是大量的源代码修改,这显示是违法了咱们的开闭原则。android
接着是,如何引入新替换的网络加载库,这至关因而新添加了另一个网络库的各类请求功能。最终的效果就是咱们使用着不一样的网络库来完成相同的功能,既然功能是一致的,那么咱们就须要考虑如何规范他们的功能(函数)定义。git
基于以上两点的考虑,咱们采用代理模式来实现咱们的网络库隔离框架。github
(1)代理模式:为其余对象提供一种代理以控制对这个对象的访问 (2)Proxy代理类:用来替代实际的网络加载库,避免界面代码与实际的网络加载直接交互 (3)RealSubject:真实请求类,在咱们的案例中,就是一种网络加载库。每添加一种网络请求库,即添加一个对应的真实请求类便可(这里就是根据不一样的网络加载库,实际进行请求功能的地方) (4)Subject:用来规范新添加的各类网络加载库以及代理类的功能使用。为何要规范代理的功能?由于代理类,代理的是真实类的功能行为,所以代理类须要与真实类的功能保持一致。json
// 代理模式中,用于规范代理类与真实类的功能接口
// 咱们暂且只定义了get和post功能
// ICallBack函数是自定义的请求回调类,后续介绍
interface IHttpProxy {
fun getHttp(url: String, callback: ICallBack)
fun postHttp(url: String, params: Map<String, Any>, callback: ICallBack)
}
复制代码
// 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方法表示的是传入当前须要被代理的真实类对象设计模式
// 实现代理模式中的接口
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
// 最底层的回调类,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<*>
}
}
复制代码
// 一个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()) // 设置真实代理对象
}
}
复制代码
(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()) // 设置为新网络加载类对象
}
复制代码
}
至此,咱们的网络隔离库框架雏形已搭建完毕,更多的功能请自定扩展。若有任何不正确地方,欢迎批评指正。 很是感谢【腾讯课堂-Android高级开发专题课】
【项目地址】:github.com/y0000c/Http…