緣起
頁面狀態管理是每個app都要考慮的問題--第一次進入顯示正在加載中的頁面,內容為空的頁面,發生錯誤頁面.
段位低一點的,在BaseActivity和BaseFragment中寫個方法
段位高一點的,自己造一個包含這幾個狀態的Layout的輪子(LoadingLayout之類的),在layout文件中使用.
but,每次要管理頁面狀態時都要在xml中用這個layout包裹我們的內容,不繁瑣么?有沒有更好的方法?
有的,看這里PageStateManager.不用修改xml,直接一行代碼調用就可以嵌入那幾個帶狀態的頁面.(基于張鴻洋的LoadingAndRetryManager改寫而來的,封裝了常用邏輯,優化了相關api).
原理
用代碼來插入一層Framelayout來管理頁面狀態,而不是自己手寫到xml.
參數傳入需要管理的activity/fragment/view,
然后拿到對應的contentview/view的parent
將contentview/view從parent中移除.
new 一個framlayout,添加loading,error,empty的view,同時也添加contentview/view.
將這個framlayout添加到parent.
提供一個管理類來配置loading,error,empty,以及控制其顯示與隱藏操作.
核心代碼
contentParent.removeView(oldContent);
//setup content layout
PageLayout loadingAndRetryLayout = new PageLayout(context);
ViewGroup.LayoutParams lp = oldContent.getLayoutParams();
contentParent.addView(loadingAndRetryLayout, index, lp);
loadingAndRetryLayout.setContentView(oldContent);
// setup loading,retry,empty layout
setupLoadingLayout(listener, loadingAndRetryLayout);
setupRetryLayout(listener, loadingAndRetryLayout);
setupEmptyLayout(listener, loadingAndRetryLayout);
api設計
要設計一個適合大多數應用的頁面狀態管理類,知曉大多數app的頁面管理邏輯即可,哪里用得著提供那么多的setXxx來高度自定義樣式?
- 每個app的狀態頁面都有自己的風格,所以在Application中初始化時,應該有設置這幾個頁面的方法.
- app內部,"加載中"的頁面一般全app都是統一的,不會出現這個頁面的loading狀態頁和那個頁面的loading狀態頁不一致的情況.
- app內部,空白頁面一般由圖片+文字構成,圖片大多一致,而文字說明可能會不一致.
- app內部,錯誤頁面一般由圖片+說明文字+重試按鈕 組成,說明文字一般都會不一致.
- 點擊錯誤頁面按鈕后重試,重試的邏輯一般是,判斷有沒有網絡,沒有就去設置,有的話就重新執行網絡請求.
- 考慮到確實有的地方狀態頁面跟整個app的完全不同,也提供了在頁面內獨立設置這幾個狀態頁面的API.
基于上面的思路,提供的API有:
BaseApplication里的初始化
public static void initInApp(Context appContext)//使用默認提供的幾個狀態頁面
/**
自定義狀態頁面,傳入相應的layout文件的id即可.
* 如果需要后續調用自定義空白msg,錯誤msg字符串的api,則頁面中顯示該字符串的textview的id必須為tv_msg_empty,tv_msg_error
*/
public static void initInApp(Context appContext,int layoutIdOfEmpty,int layoutIdOfLoading,int layoutIdOfError)
頁面中生成PageManager對象
/**
*
* @param container 必須為activity,fragment或者view.如果是view,則該view對象必須有parent
* @param retryAction 點擊重試的動作,注意,只需要關注有網絡的情況,無網絡狀態時已經封裝好:彈出對話框詢問用戶是否去設置網絡
* @param isShowLoadingOrContent 第一次是顯示loading(true)還是content(false)
* @return 當前頁面的狀態管理器
*/
public static PageManager init(final Object container, boolean isShowLoadingOrContent ,final Runnable retryAction)
//如果當前頁面的空白狀態下,提示語需要自定義,則調用此方法
public static PageManager init(final Object container, final CharSequence emptyMsg, boolean isShowLoadingOrContent ,final Runnable retryAction)
控制頁面狀態
public void showLoading()
public void showContent()
public void showEmpty()
public void showError()
public void showError(CharSequence errorMsg)
如果需要針對單個Activity、Fragment、View定制頁面,則調用generate方法,并重寫 一個重寫接口的回調方法:
PageManager.generate(this, new PageListener() {
@Override
public void setRetryEvent(View retryView) {
}
@Override
public int generateEmptyLayoutId() {
return super.generateEmptyLayoutId();
}
@Override
public int generateLoadingLayoutId() {
return super.generateLoadingLayoutId();
}
@Override
public int generateRetryLayoutId() {
return super.generateRetryLayoutId();
}
});
默認提供了三個狀態頁:
注意事項
1.給view對象設置狀態時,該對象必須有parent.
2.失敗頁面的無網絡狀態已經處理,runnable里只需要包裝有網絡時的處理動作.