Gloading

Gloading是一個github開源項目,可以用來深度解耦Android App中全局載入中、載入失敗及空數據視圖,也用這個項目中的思路可以進行類似的View解耦情形。

基本介紹

  • 外文名:Gloading
  • 開發語言:android(java)
  • 開源時間:2019-03-17
  • 作用:解耦
主要特點,背景介紹,解耦方式,使用Gloading來解耦,

主要特點

  • 深度解耦Android App中全局載入中、載入失敗及空數據視圖,為組件化改造過程中的解耦長征助力
  • 分離全局載入狀態視圖的實現和使用
  • 不需要在每個頁面的布局檔案中額外添加載入狀態視圖
  • 可用於Activity、Fragment,也可用於為某個View顯示載入狀態,還可用於各種列表Item(ListView、RecyclerView等)
  • 輕量級:只有一個java檔案,沒有任何其它依賴,不到300行,其中注釋占100+行,aar僅6K
  • 兼容性好:
  • android系統版本從api 1開始兼容
  • 兼容絕大多數第三方炫酷的LoadingView(在Adapter中將其作為View提供給Gloading)

背景介紹

Loading動畫幾乎每個Android App中都有。
一般在需要用戶等待的場景,顯示一個Loading動畫可以讓用戶知道App正在載入數據,而不是程式卡死,從而給用戶較好的使用體驗。
同樣的道理,當載入的數據為空時顯示一個數據為空的視圖、在數據載入失敗時顯示載入失敗對應的UI並支持點擊重試會比白屏的用戶體驗更好一些。
載入中、載入失敗、空數據的UI風格,一般來說在App內的所有頁面中需要保持一致,也就是需要做到全局統一。
傳統的做法
  1. 定義一個(或多個)顯示不同載入狀態的控制項或者xml布局檔案(例如:LoadingView)
  2. 每個頁面的布局中都寫上這個view
  3. 在BaseActivity/BaseFragment中封裝LoadingView的初始化邏輯,並封裝載入狀態切換時的UI顯示邏輯,暴露給子類以下方法:
  4. void showLoading;//調用此方法顯示載入中的動畫
  5. void showLoadFailed;//調用此方法顯示載入失敗界面
  6. void showEmpty;//調用此方法顯示空頁面
  7. void onClickRetry;//子類中實現,點擊重試的回調方法
  8. 在BaseActivity/BaseFragment的子類中可通過上一步的封裝比較方便地使用載入狀態顯示功能
這種使用方式耦合度太高,每個頁面的布局檔案中都需要添加LoadingView,使用起來不方便而且維護成本較高,一旦UI設計師需要更改布局,修改起來成本較高。
好一點的封裝方法
  1. 定義一個(或多個)顯示不同載入狀態的控制項或者xml布局檔案(例如:LoadingView)
  2. 定義一個工具類(LoadingUtil)來管理LoadingView,不同狀態顯示不同的UI(或者在多個View之間切換顯示)
  3. 在BaseActivity/BaseFragment中對LoadingUtil的使用進行封裝,暴露給子類以下方法:
  4. void showLoading;//調用此方法顯示載入中的動畫
  5. void showLoadFailed;//調用此方法顯示載入失敗界面
  6. void showEmpty;//調用此方法顯示空頁面
  7. void onClickRetry;//子類中實現,點擊重試的回調方法
  8. abstract int getContainerId;//子類中實現,LoadingUtil動態創建LoadingView並添加到該方法返回id對應的控制項中
  9. 在BaseActivity/BaseFragment的子類中可通過上一步的封裝比較方便地使用載入狀態顯示功能
這種封裝的好處是通過封裝動態地創建LoadingView並添加到指定的父容器中,讓具體頁面無需關注LoadingView的實現,只需要指定在哪個容器中顯示即可,很大程度地進行了解耦。如果公司只在一個App中使用,這基本上就夠了。
但是,這種封裝方式還是存在耦合:頁面與它所使用的LoadingView仍然存在綁定關係。如果需要復用到其它App中,因為每個App的UI風格可能不同,對應的LoadingView布局也可能會不一樣,要想復用必須先將頁面與LoadingView解耦。

解耦方式

梳理一下我們需要實現的效果
  • 頁面的LoadingView可切換,且不需要改動頁面代碼
  • 頁面中可指定LoadingView的顯示區域(例如導航欄Title不希望被LoadingView覆蓋)
  • 支持在Fragment中使用
  • 支持載入失敗頁面中點擊重試
  • 兼容不同頁面顯示的UI有細微差別(例如提示文字可能不同)
2. 確定思路
說到View的解耦,很容易聯想到Android系統中的AdapterView(我們常用的GridView和ListView都是它的子類)及support包里提供的ViewPager、RecyclerView等,它們都是通過Adapter來解耦的,將自身的邏輯與需要動態變化的子View進行分離。我們也可以按照這個思路來解耦LoadingView。

使用Gloading來解耦

Gloading是一個基於Adapter思路實現的深度解耦App中全局LoadingView的輕量級工具(只有一個java檔案,不到300行,其中注釋占100+行,aar僅6K)
1、 依賴Gloading
compile 'com.billy.android:gloading:1.0.0'
2、 創建Adapter,在getView方法中實現創建各種狀態視圖(載入中、載入失敗、空數據等)的邏輯
Gloading不侵入UI布局,完全由用戶自定義
3、 初始化Gloading的默認Adapter
Gloading.initDefault(new GlobalAdapter());
註:可以用AutoRegister在Gloading類裝載進虛擬機時自動完成初始化註冊,無需在app層執行註冊,耦合度更低
4、在需要使用LoadingView的地方獲取Holder
//在Activity中顯示, 父容器為: android.R.id.content
Gloading.Holder holder = Gloading.getDefault().wrap(activity);
//需要支持載入失敗後點擊重試
Gloading.Holder holder = Gloading.getDefault().wrap(activity).withRetry(retryTask);
or
//為某個View顯示載入狀態
//Gloading會自動創建一個FrameLayout,將view包裹起來,LoadingView也顯示在其中
Gloading.Holder holder = Gloading.getDefault().wrap(view);
//需要支持載入失敗後點擊重試
Gloading.Holder holder = Gloading.getDefault().wrap(view).withRetry(retryTask);
5、 使用Holder來顯示各種載入狀態
//顯示載入中的狀態,通常是顯示一個載入動畫
holder.showLoading()
//顯示載入成功狀態(一般是隱藏LoadingView)
holder.showLoadSuccess()
//顯示載入失敗狀態
holder.showFailed()
//數據載入完成,但數據為空
holder.showEmpty()
//如果以上默認提供的狀態不能滿足使用,可使用此方法調用其它狀態
holder.showLoadingStatus(status)
6、 兼容多App場景下的頁面、View的復用
每個App的LoadingView可能會不同,只需為每個App提供不同的Adapter,不同App調用不同的Gloading.initDefault(new GlobalAdapter);,具體頁面中的使用代碼無需改動。
註:如果使用AutoRegister,則只需在不同App中創建各自的Adapter實現類,無需手動調用Gloading.initDefault註冊。只需改動2處gradle檔案即可:
  • 修改根目錄build.gradle,添加對AutoRegister的依賴
buildscript {  
  
  //...
  
  dependencies {
    
//...
    classpath 'com.billy.android:autoregister:使用最新版'
  }
}
  • 修改主application module下的build.gradle,添加如下代碼即可實現Adapter的自動註冊
apply plugin: 'auto-register'
autoregister {
  registerInfo = [
       [
         
  'scanInterface'             : 'com.billy.android.loading.Gloading$Adapter'
           , 'codeInsertToClassName'   : 'com.billy.android.loading.Gloading'
           , 'registerMethodName'      : 'initDefault'
       ]
   ]
}

熱門詞條

聯絡我們