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…

相關文章
相關標籤/搜索