打造Android輕量級框架XSnow的後繼之路

前言

因爲有使用的朋友提到 XSnow 框架信息量有點大,但願能有篇文章詳細介紹框架中每一個模塊的細節,因此本文會圍繞該框架將每個模塊的相關構思和重要技術點作一個詳細的剖析,讓使用該框架的朋友對 XSnow 有一個清晰的認識。html

準備

因爲 XSnow 框架是基於 RxJava2Retrofit2 打造的,其中也依賴瞭如網絡基礎庫 OkHttp 、圖片加載庫 Glide 、數據庫基礎庫 GreenDao ,因此使用該項目的朋友須要對這幾個基礎框架有基本的認識,下面將對這幾個框架作一個簡單的說明。java

RxJava

熟悉的朋友可能知道該框架是屬於 ReactiveX 編程庫的一員,這是一種新的編程思想,通常都把它叫作響應式編程思想,對於使用該思想的優點在這裏就不贅述了,感興趣的朋友能夠看看這篇文章 ReactiveX 文檔中文翻譯git

RxJava 主要的模式就是觀察者模式,何爲觀察者模式,能夠簡單的理解爲:兩個對象觀察者與被觀察者,其中觀察者與被觀察者創建了訂閱關係,若是被觀察者發生了變化那麼須要及時通知觀察者,觀察者收到通知後作出相應的處理。描述可能會有點繞,舉個通俗易懂的例子吧,好比說:顧客去買蛋糕這樣一個場景(把顧客和蛋糕店店員分別看作觀察者與被觀察者),因爲蛋糕是現作須要必定時間才能完成,顧客在購買時通常會先付錢給店員拿到一個付款憑證後離開去忙其餘事,這樣他們就創建了購買關係(創建訂閱關係),店員在作完蛋糕後(被觀察者發生變化),店員就會通知顧客來拿(消息通知到觀察者),顧客在收到店員通知後前來拿蛋糕(觀察者收到通知後作出相應的處理)。到這裏,一個完整的觀察者模式場景就講解完畢,但願能幫助朋友們加深對觀察者模式的理解。github

下面繼續講解對 RxJava 的理解,先想象一個這樣的場景,有一臺萬能機器,它能夠生產任何東西,它有一個輸入端、一個輸出端,中間有不少核心組件,好比說轉換器、轉移器等,它們對外部都是隱藏的,可是外部有一個控制終端,能夠輸入任何想要的規則,機器就會根據規則,將輸入端的東西經過終端制定的規則輸送到輸出端。RxJava 就是這樣一臺萬能機器,它擁有數據輸入端、數據輸出端,中間也有不少能夠操控數據的規則,好比說各類操做符、線程轉換,它們都有一個目的,就是如何讓數據源經過必定規則進行輸出。算法

以上的講解只是爲了讓你對 RxJava 有一個清晰的認識,不牽扯具體的技術細節,若是想詳細瞭解的能夠去看看給初學者的 RxJava2.0 教程,這是一個系列,看完這些文章,基本就可使用 RxJava 作一些基礎的功能了,這個系列是針對 RxJava2 的,若是想了解 RxJava 初版,想看看兩個版本到底發生了什麼改變,那麼能夠看看給 Android 開發者的 RxJava 詳解以及 RxJava2 vs RxJava1.數據庫

Retrofit

Retrofit 簡單來講就是一個基於 OkHttpRESTful API 請求工具。RESTful 是一種架構風格,它的特色是資源、統一接口、URI 和無狀態,若是想更詳細的瞭解 RESTful 能夠看看RESTful 架構風格概述編程

Retrofit 在使用時其實就充當了一個適配器(Adapter)的角色,主要是將一個 Java 接口翻譯成一個 HTTP 請求對象,而後用 OkHttp 去發送這個請求。其中核心思想就是動態代理機制,什麼是動態代理,就是當你要調用某個 Class 的方法前或後,插入你想要執行的代碼。通俗來說,就是你要執行某個操做的先後須要增長一些操做,好比查看用戶我的信息前須要判斷用戶是否登陸,用戶訪問數據庫後想清除用戶的訪問記錄等操做。api

Retrofit 的設計很是插件化且輕量級,高內聚且低耦合。
Retrofit 主要定義了 4 個接口:數組

  • Callback<T>:請求數據的返回;
  • Converter<F, T>:對返回數據進行解析,通常用 GSON
  • Call<T>:發送請求,Retrofit 默認的實現是 OkHttpCall<T>,也能夠依需自定義 Call<T>
  • CallAdapter<T>:將 Call 對象轉換成其餘對象,如轉換成支持 RxJavaObservable 對象。

Retrofit 進行網絡請求的過程:緩存

  • 經過 Retrofit 對象和 Method 對象獲取 callAdapterresponseType 以及 responseConverter 三個對象;
  • 經過解析 Method 中的註解以及進行一系列的檢查獲得中心管理對象 ServiceMethod
  • 經過 ServiceMethod 對象獲取實際執行的 Call 對象執行 Http 請求。

以上講解只是對 Retrofit 的核心功能作了相關的解釋,若是想更詳細的瞭解 Retrofit 能夠看看拆輪子系列:拆 Retrofit

OkHttp

OkHttp 是一個高效的 HTTP 庫,它的整體設計圖以下(圖片來源:泡在網上的日子):

OkHttp整體設計圖
OkHttp整體設計圖

OkHttp 的請求由 OkHttpClient 統一管理,採用的是門面模式,OkHttpClient 擁有子模塊的全部配置和參數,並將請求分發到相應的子系統。它由如下幾個核心子系統組成:路由、鏈接協議、攔截器、代理、安全性認證、鏈接池以及網絡適配。主要是經過 Dispatcher 不斷從 RequestQueue 中取出請求(Call),根據是否已緩存調用 CacheNetwork 這兩類數據來獲取某個接口,再從內存緩存或是服務器取得請求的數據。該引擎有同步和異步請求,同步請求經過Call.execute()直接返回當前的 Response,而異步請求會把當前的請求(AsyncCallCall.enqueue 添加到請求隊列中,並經過回調(Callback)的方式來獲取最後結果。

OkHttp 中的 Interceptor(攔截器)方式對於總體的設計提供了很大的幫助,它採用的是責任鏈模式,它不僅是負責攔截請求進行一些額外的處理(例如增長請求頭),實際上它把實際的網絡請求、緩存、透明壓縮等功能都統一了起來,每個功能都只是一個 Interceptor,它們再鏈接成一個 Interceptor.Chain,環環相扣,最終圓滿完成一次網絡請求。

以上講解只是對 OkHttp 的流程作了相關的解釋,若是想更詳細的瞭解 OkHttp 能夠看看拆輪子系列:拆 OkHttp

Glide

Glide 是爲圖片加載而生,一行代碼Glide.with(this).load(url).into(imageView);就搞定圖片的加載。使用很是簡單,若是想詳細瞭解的,這裏推薦郭霖的 Glide 源碼解析,Android 圖片加載框架最全解析,這是一個系列,看完後對於 Glide 基本就能知道怎麼用和爲啥要這樣用了。

GreenDao

GreenDao 是一個將對象映射到 SQLite 數據庫中的輕量且快速的 ORM 解決方案。若是想更詳細的瞭解 GreenDao 能夠看看Android 數據存儲之 GreenDao 3.0 詳解

注:

  • 以上對於基礎庫的講解只是作了簡單的介紹,讓你對 XSnow 框架利用的相關技術有個直觀的感覺,若是想詳細瞭解的,上面在每一個基礎庫後面都備註了我的認爲比較好的文章,能夠當作學習該框架的參考。
  • 如下介紹都以包名做爲每一個模塊的標題,這樣也代表模塊之間充分解耦,也方便讀者對照代碼進行理解,分析起來邏輯更清晰。

Http(網絡模塊,包含網絡請求,上傳下載)

該模塊是 XSnow 框架的核心功能,其核心思想就是將請求分離和基於動態配置,採用門面模式,上層不用關係具體實現細節,只須要簡單配置相關的請求信息就能夠達到完整的網絡請求功能。該模塊相對於其餘模塊代碼量比較大,下面將會對該模塊下的每個包進行詳細拆分講解,如今咱們首先來看看 ViseHttp 類,該類至關於該模塊的門面類,也是網絡請求的惟一入口類,全部的請求都是由該類構建,如:

  • BASE:傳入自定義請求對象,方便外部根據本身的需求自定義請求;
  • GET:獲取 GET 方式請求對象;
  • POST:獲取 POST 方式請求對象;
  • HEAD:獲取 HEAD 方式請求對象;
  • PUT:獲取 PUT 方式請求對象;
  • PATCH:獲取 PATCH 方式請求對象;
  • OPTIONS:獲取 OPTIONS 方式請求對象;
  • DELETE:獲取 DELETE 方式請求對象;
  • UPLOAD:獲取上傳文件請求對象,支持傳入上傳回調;
  • DOWNLOAD:獲取下載文件請求對象。

該類還提供了根據 tag 中斷單個網絡請求以及中斷全部網絡請求功能,也提供了根據 key 刪除緩存和清除全部網絡緩存功能。必須注意的是,在應用初始化時必須調用該類的初始化方法

ViseHttp.init(this);複製代碼

以及相關的網絡配置

ViseHttp.CONFIG()
        //配置請求主機地址
        .baseUrl("http://10.8.4.39/")
        //配置全局請求頭
        .globalHeaders(new HashMap<String, String>())
        //配置全局請求參數
        .globalParams(new HashMap<String, String>())
        //配置讀取超時時間,單位秒
        .readTimeout(30)
        //配置寫入超時時間,單位秒
        .writeTimeout(30)
        //配置鏈接超時時間,單位秒
        .connectTimeout(30)
        //配置請求失敗重試次數
        .retryCount(3)
        //配置請求失敗重試間隔時間,單位毫秒
        .retryDelayMillis(1000)
        ......;複製代碼

這樣才能在應用中調用相關的網絡請求功能。若是沒有初始化,在調用網絡請求時該模塊會拋出以下異常信息:

Please call ViseHttp.init(this) in Application to initialize!複製代碼

切記!

下面來分別講解該模塊下每一個包的功能:

  • api
    該包提供的是請求的 API,目前只有一個類 ApiService,主要提供的是 Retrofit 進行網絡請求的請求方法。

  • body
    該包提供的是相關的請求和響應 body,目前只有一個上傳進度展現的請求實體類 UploadProgressRequestBody,經過傳入 UCallback 來處理上傳文件的進度回調。

  • callback
    該包提供的是相關的回調類,目前包含上傳回調 UCallback 和請求 API 回調 ACallback

  • config
    該包提供的是配置相關類,目前只有請求全局配置類 HttpGlobalConfig,該類提供了很豐富的配置方法,提供該類的目的是想將配置與請求分離。

  • core
    該包提供的是一些核心功能類,目前包含緩存處理類 ApiCacheCookie 管理類 ApiCookie 以及網絡請求訂閱管理類 ApiManager。緩存採用磁盤緩存方式,支持定製各類緩存策略,策略將在 strategy 包下進行講解。Cookie 採用 SharedPreferences 存儲,存儲對象以十六進制進行保存。

  • exception
    該包提供網絡請求相關異常類,目前提供了請求異常統一處理類 ApiException,可用來斷定請求失敗的緣由。

  • func
    該包提供一些數據轉換類,目前提供了由 ResponseBody 對象轉 TApiFunc<T> 類以及由 Observable<? extends Throwable>Observable<?>ApiRetryFunc 類。ApiRetryFunc 類主要用來處理網絡超時重試機制,可傳入重試次數和重試間隔時間,這些均可以在配置類中進行配置。

  • interceptor
    該包提供的是一系列的攔截器類,這個包也算是該模塊的核心包,基本大部分功能均可以採用攔截器的方式來提供,目前該包下面包含以下攔截器:
    一、GzipRequestInterceptor:包含Gzip壓縮的請求攔截;
    二、HeadersInterceptor:請求頭攔截;
    三、HttpLogInterceptor:Http日誌打印攔截;
    四、NoCacheInterceptor:無緩存攔截;
    五、OfflineCacheInterceptor:離線緩存攔截;
    六、OnlineCacheInterceptor:在線緩存攔截;
    七、UploadProgressInterceptor:上傳文件進度展現攔截。

  • mode
    該包提供的是相關的實體類。

  • request
    該包提供的是全部請求相關的類,全部的網絡請求都須要建立一個請求對象,該包提供了一個基礎請求類 BaseRequest<R extends BaseRequest>,該類需將 R 寫成實際請求類,這樣才能獲取對應請求類的對象來進行相關的請求信息配置,若是請求配置與全局配置衝突,那麼優先請求配置,意思就是局部請求配置會替換掉相同的全局配置。
    請求類中提供了一系列請求頭配置、請求參數配置等信息,若是是 POST 請求還提供了上傳 JSON 字符串、上傳表單等方式,而若是是上傳文件則提供了添加文件、添加字節數組和添加流的方式。
    因爲帶緩存請求和不帶緩存請求返回的結果不同,因此須要分開處理,故有 cacheExecuteexecute 的區分。

  • strategy
    該包提供的是緩存相關的策略,包含以下幾種策略:
    一、CacheAndRemoteStrategy:先加載緩存數據後加載網絡數據;
    二、FirstCacheStrategy:優先加載緩存數據;
    三、FirstRemoteStrategy:優先加載網絡數據;
    四、OnlyCacheStrategy:只加載緩存數據;
    五、OnlyRemoteStrategy:只加載網絡數據。
    緩存策略採用面向接口編程原則,定義了一個緩存策略接口 ICacheStrategy<T>,並將具體的策略實現交由各個子類。

  • subscriber
    該包提供的是相關的訂閱者,目前包含 API 請求的統一訂閱者 ApiSubscriber<T>、包含回調的訂閱者 ApiCallbackSubscriber<T> 以及包含下載回調的訂閱者 DownCallbackSubscriber<T>

Cache(緩存)

該模塊提供了幾種緩存方式,分別是內存緩存、磁盤緩存以及 SharedPreferences 存儲。該模塊主要思想是面向接口編程,提供了 ICache 接口,主要包含添加緩存、獲取緩存、刪除緩存、清除全部緩存以及判斷是否包含該緩存這幾個能力。下面將對每一個緩存方式作詳細的解釋說明:

  • 內存緩存:內存緩存採用單例模式管理緩存對象,緩存對象爲 LruCache,緩存算法採用 Lru 算法(Least Recently Used 近期最少使用算法),緩存大小爲最大內存的八分之一。
  • 磁盤緩存:磁盤緩存 KEY 採用 MD5 加密,可定製緩存時長,沒有定製則默認永久存儲,緩存對象爲 DiskLruCache,緩存算法也是 Lru 算法,緩存位置和緩存大小均可以定製,若是沒有定製就會使用默認值,默認的緩存位置爲該應用緩存目錄下的 disk_cache 目錄,優先存儲到 SD 卡中,默認的緩存大小爲 20M
  • SharedPreferences 存儲:SharedPreferences 存儲對緩存對象進行 Base64 加密存儲,可定製緩存文件名,若是沒有定製則使用默認文件名 sp_cache

Event(事件總線)

該模塊使用 Rx 思想實現了 RxBus 功能,其 Bus 的設計思想與 EventBus 相似。其主要由如下幾個核心類組成:

  • EventBase :事件處理基類,包含粘性事件 Map 以及普通事件 Subject,也定義了獲取 Flowable 以及刪除粘性事件和刪除粘性事件 Map 的方法。
  • EventComposite :事件複合類,就是將須要接收事件的類中全部事件組合到一塊兒進行處理,並提供了一個發送粘性事件的方法。
  • EventSubscriber :事件訂閱者,提供了訂閱事件和分發事件的方法。
  • EventFind :根據註解查找事件接收方法,由此獲得 EventSubscriber,最後組合到一塊兒獲得 EventComposite
  • ThreadMode :線程模型,包含如主線程、IO線程等,經過 getScheduler(ThreadMode thread) 來獲取線程調度者。

事件接收採用註解方式類進行管理,事件訂閱後依據註解來查找對應的事件接收地。

該模塊爲了能將事件總線統一,定義了 IBus 接口,提供了以下四個方法:

void register(Object object);

void unregister(Object object);

void post(IEvent event);

void postSticky(IEvent event);複製代碼

也提供了 IEvent 接口,全部事件都實現該接口,這樣就能夠將具體的事件實現類抽離,其實也是面向接口編程。

該模塊也提供了插件化思想,上層能夠將如 EventBus 的實現類注入該模塊,那麼事件的處理就會採用 EventBus 實現的策略,但這裏有一個問題,因爲事件接收採用的是註解方式,而 EventBus 中的註解是不一樣的,因此仍是須要把註解事件進行統一替換,耦合性過高,目前沒有發現更好的方式,若是哪位朋友有好的去耦合方式,歡迎留言交流!

Loader(圖片加載)

該模塊針對圖片加載作了二次封裝,面向接口編程,每一個實現就是一種圖片加載策略,默認採用 Glide 圖片加載框架,上層也能夠依需自定義實現接口 ILoader,好比 Demo 中提供的 Fresco 圖片框架的實現類 FrescoLoader,其主要思想就是插件化,外部可注入任何加載策略,這樣可達到高內聚低耦合。

接口中提供了以下四種加載圖片的方式:

  • 加載網絡圖片
    void loadNet(ImageView target, String url, Options options);複製代碼
  • 加載資源圖片
    void loadResource(ImageView target, int resId, Options options);複製代碼
  • 加載Assets中的圖片
    void loadAssets(ImageView target, String assetName, Options options);複製代碼
  • 加載本地圖片
    void loadFile(ImageView target, File file, Options options);複製代碼

默認的 Glide 框架採用 provided 方式依賴,這樣就只是編譯時依賴,運行時不依賴,上層若是肯定使用 GlideLoader加載策略,那麼還須要本身使用 compile 進行依賴,這樣運行時纔不會報錯,GlideLoader 在初始化時也增長了以下驗證機制

try {
    Class.forName("com.bumptech.glide.Glide");
} catch (ClassNotFoundException e) {
    throw new IllegalStateException("Must be dependencies Glide!");
}複製代碼

若是沒有依賴 Glide 庫則會拋出異常。

Database(數據庫)

該模塊將 GreenDao 做爲底層數據庫,定義了數據庫的操做接口 IDatabase<M, K>,統一由 DBManager<M, K> 抽象類管理,因爲每一個實體類對應的 Dao 不同,因此定義了抽象方法 getAbstractDao()。因爲 GreenDao 的特殊性,該方法的實現類不能在框架中搭建,全部數據庫操做均可以參考 DemoDbHeDlper 類實現本身的數據庫操做管理類,不一樣的 Dao 實現對應的 getAbstractDao() 方法就行。

Permission(權限管理)

該模塊利用 Rx 思想統一管理權限的申請,一行代碼搞定權限的申請問題。

PermissionManager.instance().with(this).request(onPermissionCallback, Manifest.permission.CALL_PHONE);複製代碼

該模塊很簡潔,就幾個類,下面分別對它們進行介紹:

  • OnPermissionCallback:權限申請回調接口,在接口實現類中調用具體的業務邏輯。
  • Permission:權限實體類,包含權限名稱、是否授予權限以及是否顯示權限申請理由變量。
  • PermissionManager:權限管理類,也是權限申請的惟一入口,採用單例模式,須要經過 with 將當前的 Activity 對象傳進去,調用 request 方法就能夠進行權限申請,須要傳入回調和權限列表,權限列表採用可變數組方式傳入,使用示例以下:

    PermissionManager.instance().with(this).request(new OnPermissionCallback() {
      @Override
      public void onRequestAllow(String permissionName) {
          DialogUtil.showTips(mContext, getString(R.string.permission_control),
                  getString(R.string.permission_allow) + "\n" + permissionName);
      }
    
      @Override
      public void onRequestRefuse(String permissionName) {
          DialogUtil.showTips(mContext, getString(R.string.permission_control),
                  getString(R.string.permission_refuse) + "\n" + permissionName);
      }
    
      @Override
      public void onRequestNoAsk(String permissionName) {
          DialogUtil.showTips(mContext, getString(R.string.permission_control),
                  getString(R.string.permission_noAsk) + "\n" + permissionName);
      }
    }, Manifest.permission.CALL_PHONE);複製代碼
  • RxPermissions:權限管理核心類,該類經過傳入 Activity 獲取一個 Fragment 來進行權限申請回調處理,提供了一系列權限申請的方法,有多個權限單獨處理回調和統一處理回調的方式,分別是 requestEachrequest 方式。
  • RxPermissionsFragment:權限申請回調處理 Fragment

UI(UI模塊,包含萬能適配器、視圖切換)

該模塊包含萬能適配器和試圖切換功能。適配器部分採用 ViewHolder 來管理數據的裝載和展現,將數據與展現分離,提供了 DataHelper 接口來裝載數據,ViewHelper 接口來處理 UI 的展現。其中的 HelperAdapter 提供了適配器的經常使用方法,基本能知足適配器的經常使用需求。
視圖切換部分由 StatusLayoutManager 統一管理,經過傳入相關配置進行視圖展現處理。內部提供了 OnRetryListener 重試監聽和 OnStatusViewListener 試圖切換監聽,並定義了一個自定義視圖 StatusLayout 用來展現如下五種視圖:

  • CONTENT:內容視圖;
  • LOADING:加載視圖;
  • EMPTY:空視圖;
  • NETWORK_ERROR:網絡錯誤視圖;
  • OTHER_ERROR:其餘錯誤視圖。

最後

到此,XSnow 框架的全部模塊就介紹完畢了,不知各位朋友是否對該框架有了更深刻的瞭解。

以上描述有些部分可能講解比較簡單,這是由於有些模塊自己不是很複雜,因此就沒有作過多的講解,若是想更清晰的瞭解該框架,最好的辦法是直接 down 下源碼觀察,若是在看源碼過程當中有哪裏不理解或以爲實現有問題而你有更好的方案均可以留言交流!

源碼地址:github.com/xiaoyaoyou1…,源碼地址中提供了詳細的使用文檔,裏面有版本介紹以及QQ羣等信息,若是喜歡該框架不妨點點 star 並分享給身邊的朋友,讓更多的朋友參與進來,謝謝你們!

相關文章
相關標籤/搜索