1. 程式人生 > >介紹一下頁面狀態管理類PageStateManager,我實在看不下去你們直接用Layout

介紹一下頁面狀態管理類PageStateManager,我實在看不下去你們直接用Layout

緣起

頁面狀態管理是每個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來高度自定義樣式?

  1. 每個app的狀態頁面都有自己的風格,所以在Application中初始化時,應該有設定這幾個頁面的方法.
  2. app內部,”載入中”的頁面一般全app都是統一的,不會出現這個頁面的loading狀態頁和那個頁面的loading狀態頁不一致的情況.
  3. app內部,空白頁面一般由圖片+文字構成,圖片大多一致,而文字說明可能會不一致.
  4. app內部,錯誤頁面一般由圖片+說明文字+重試按鈕 組成,說明文字一般都會不一致.
  5. 點選錯誤頁面按鈕後重試,重試的邏輯一般是,判斷有沒有網路,沒有就去設定,有的話就重新執行網路請求.
  6. 考慮到確實有的地方狀態頁面跟整個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();
        }
    });

預設提供了三個狀態頁:

loading.jpg

empty.jpg

error.jpg

error_dialog.jpg

注意事項

1.給view物件設定狀態時,該物件必須有parent

2.失敗頁面的無網路狀態已經處理,runnable裡只需要包裝有網路時的處理動作.

# 程式碼地址

ps.
csdn的markdown很難用,都好久沒上這裡來了