Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 加載3種狀態架構

加載3種狀態架構

編輯:關於Android編程

基類LoadintPager(加載三種狀態)

通常都知道,android中一個頁面的加載,無非三種狀態:

加載中 加載成功 加載失敗

當然,如果從網絡獲取數據,可能會出現數據為空的情況。這裡也要考慮進去
具體看下截圖

失敗

\

加載成功,這裡界面隨意弄的textview

\

\

加載中

\

這裡可以抽下共有的方法。

/**
 * 描述:LoadingPager 不會在xml中使用,所以只實現context參數的構造
 * 作者:Marc on 2016/7/7 09:27
 * 郵箱:[email protected]
 */
public abstract class LoadingPager extends FrameLayout {

    /**
     * //頁面顯示分析
     * //Fragment共性-->頁面共性-->視圖的展示
     * /**
     * 任何應用其實就只有4種頁面類型
     * ① 加載頁面
     * ② 錯誤頁面
     * ③ 空頁面
     * ④ 成功頁面
     * <p/>
     * ①②③三種頁面一個應用基本是固定的
     * 每一個fragment/activity對應的頁面④就不一樣
     * 進入應用的時候顯示①,②③④需要加載數據之後才知道顯示哪個
     */

public static final int STATE_NONE = -1;// 默認狀態
public static final int STATE_LODING = 0;//正在請求網絡
public static final int STATE_EMPTY = 1;//空狀態
public static final int STATE_ERROR = 2;//錯誤狀態
public static final int STATE_SUCCESS = 3;// 成功狀態

public int mCurState = STATE_NONE;//當前默認狀態
private View mLoadingView;//加載中視圖
private View mErrorView;//加載錯誤視圖
private View mEmptyView;//空視圖
private View mSuccessView;//加載成功視圖


public LoadingPager(Context context) {
    super(context);
    initCommonView();
}

/**
 * 初始化常規視圖
 *
 * @call LoadingPager初始化的時候
 * @des 這初始化的時候不創建successview是因為根據不同的情況,成功界面不一樣
 */
private void initCommonView() {
    // ① 加載頁面
    mLoadingView = View.inflate(UIUtils.getContext(), R.layout.pager_loading, null);
    this.addView(mLoadingView);
    // ② 錯誤頁面
    mErrorView = View.inflate(UIUtils.getContext(), R.layout.pager_error, null);
    mErrorView.findViewById(R.id.error_btn_retry).setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            //點擊按鈕重新請求加載數據
            loadData();
        }
    });
    this.addView(mErrorView);
    // ③ 空頁面
    mEmptyView = View.inflate(UIUtils.getContext(), R.layout.pager_empty, null);
    this.addView(mEmptyView);

    refreshUI(); //第一次調用refreshUI();
}

/**
 * 刷新狀態<br>
 * <p/>
 * 根據當前狀態顯示不同的view<br>
 * 、①:.LoadingPager初始化的時候的時候調用(initCommonView()的時候調用)<br>
 * ②:顯示正在加載<br>
 * ③:正在加載數據執行完成的時候<br>
 */
private void refreshUI() {
    //控制loading視圖的顯示
    mLoadingView.setVisibility((mCurState == STATE_LODING) || (mCurState == STATE_NONE) ? View.VISIBLE : View.GONE);
    //控制errprview視圖的顯示
    mErrorView.setVisibility(mCurState == STATE_ERROR ? View.VISIBLE : View.GONE);
    //控制emptyView視圖的顯示
    mEmptyView.setVisibility(mCurState == STATE_EMPTY ? View.VISIBLE : View.GONE);
    //控制mSuccessView 視圖的顯示
    if (mSuccessView == null && mCurState == STATE_SUCCESS) {
        //創建成功視圖
        mSuccessView = initSuccess();
        this.addView(mSuccessView);
    }
    if (mSuccessView != null) {
        //控制mSuccessView的顯示隱藏
        mSuccessView.setVisibility(mCurState == STATE_SUCCESS ? View.VISIBLE : View.GONE);
    }
}


/**
 * 數據加載的流程
 * ① 觸發加載, 進入頁面開始加載/點擊某個按鈕的時候開始加載
 * ② 異步加載數據 -->顯示加載視圖
 * ③ 處理加載結果
 * ③-1、成功,顯示成功視圖
 * ③-2、失敗
 * ③-2-① 數據為空,顯示空視圖
 * ③-2-②數據加載失敗,顯示加載失敗視圖
 */

/**
 * 這個得主動調用觸發加載數據<br>
 * 暴露給外接調用, 其實就是外界觸發加載數據
 */
public void loadData() {
    //這裡有個小bug,第二次執行的時候,界面顯示由上一次的狀態決定。這裡需要重置狀態
    //為了保證每次執行的時候都是加載中視圖,而不是上一次的mCurState,也解決加載成功界面每次都重新加載的問題
    if (mCurState != STATE_SUCCESS && mCurState != STATE_LODING) {
        int state = STATE_LODING;
        mCurState = state;
        refreshUI();//第二次調用refreshUI();
        //使用線程池異步加載數據
        ThreadPoolFactory.getNormalPool().execute(new LoadDataTask());
    }
}

class LoadDataTask implements Runnable {

    @Override
    public void run() {
        //異步加載數據,通過加載的數據返回一個狀態值
        LoadResult tempState = initData();
        //處理加載結果
        mCurState = tempState.getState();
        //刷新UI,這裡需要注意的是更新Ui需要在Ui線程。所以寫了個方法
        UIUtils.postTaskSafely(new Runnable() {
            @Override
            public void run() {
                refreshUI();//第三次調用refreshUI()
            }
        });
    }
}

/**
 * 真正加載數據,必須實現,直接抽象讓子類實現<br>
 * loadData()調用的時候被調用
 *
 * @return 加載狀態返回
 */
public abstract LoadResult initData();

/**
 * 創建成功視圖,交給具體子類完成<br>
 * 返回成功視圖,正在加載數據完成之後,並且數據加載成功,我們必須告知具體的成功制圖
 *
 * @return
 */
protected abstract View initSuccess();


/**
 * 使用枚舉是,是為了不讓隨意傳值,限定值
 */
public enum LoadResult {

    SUCCESS(STATE_SUCCESS), ERROR(STATE_ERROR), EMPTY(STATE_EMPTY);
    int state;

    public int getState() {
        return state;
    }

    private LoadResult(int state) {
        this.state = state;
    }
}
}

已經注釋的很詳細.

使用

單獨在activity或者fragmnet中的話。

acivity的布局



    

    <framelayout android:id="@+id/container" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical">
</framelayout>

java代碼中

       @Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    initExtra();
    setContentView(R.layout.activity_detail);

    mContainer = (FrameLayout) findViewById(R.id.container);
    layout = (LinearLayout) findViewById(R.id.layout);
    toolbar = (Toolbar) findViewById(R.id.toolbar);
    toolbarTv = (TextView) findViewById(R.id.toolbar_tv);
    initToolbar();
    loadingPager = new LoadingPager(UIUtils.getContext()) {


        @Override
        public LoadResult initData() {
            return onInitData();
        }

        @Override
        protected View initSuccess() {
            return onLoadSuccess();
        }
    };
    mContainer.addView(loadingPager);//把loadingpager加入進去。loadingpager中有成功,失敗什麼的
    //這裡記得手動調用loadingpager的加載數據方法,不然一直在加載中
    loadingPager.loadData();
}

然後實現未實現的方法

     private LoadingPager.LoadResult onInitData() {
    //發起網絡請求 加載數據

    try {
        mDatas = mProtocol.loadData(0);//這裡寫自己的獲取數據
        if (mDatas == null) {
            return LoadingPager.LoadResult.ERROR;
        }
        return LoadingPager.LoadResult.SUCCESS;
    } catch (Exception e) {
        e.printStackTrace();
        return LoadingPager.LoadResult.ERROR;
    }
}

private View onLoadSuccess() {
    View view = View.inflate(UIUtils.getContext(), R.layout.activity_detail_item, null);

    return view;
}

fragment中

        /**
 * 描述:
 * 作者:Marc on 2016/7/22 10:03
 * 郵箱:[email protected]
 */
public class FragmentThree extends BaseFragment {

    @Override
    public void fetchData() {  //這個方法在下面的basefragment中會給出為什麼
        getmLoadingPager().loadData();
    }

    @Override
    protected View initSuccess() {
        TextView tv = new TextView(UIUtils.getContext());
        tv.setTextColor(UIUtils.getColor(R.color.black));
        tv.setText(this.getClass().getSimpleName());
        return tv;
    }

    @Override
    protected LoadingPager.LoadResult initData() {
        return LoadingPager.LoadResult.EMPTY;
    }
}

這裡給出一個自己的BaseFragment方法。不預加載。

    /**

* Description:
* Created by Administrator on 2016/7/6.
*/

public abstract class BaseFragment extends Fragment {

private LoadingPager mLoadingPager;


protected boolean isViewInitiated;
protected boolean isVisiableToUser;
protected boolean isDataInitiated;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (mLoadingPager == null) {//第一次執行
        //BaseFragment 也是基類,就定義,具體實現也得交給子類實現,
        mLoadingPager = new LoadingPager(UIUtils.getContext()) {

            //BaseFragment 也是基類,就定義,具體實現也得交給子類實現,
            @Override
            public LoadResult initData() {
                return BaseFragment.this.initData();
            }

            @Override
            protected View initSuccess() {
                return BaseFragment.this.initSuccess();
            }
        };
    }

// else {
// ((ViewGroup) mLoadingPager.getParent()).removeView(mLoadingPager);
// }
return mLoadingPager;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    LogUtils.sf(getClass().getSimpleName() + "onActivityCreated");
    isViewInitiated = true;
    prepareFetchData();
}


@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    LogUtils.sf(getClass().getSimpleName() + "setVisiableToUser" + "==" + isVisibleToUser);
    this.isVisiableToUser = isVisibleToUser;
    prepareFetchData();
}


public abstract void fetchData();

public boolean prepareFetchData() {
    boolean b = prepareFetchData(false);
    return b;
}

/**
 * 是否預加載
 *
 * @param forceUpdate
 * @return
 */
public boolean prepareFetchData(boolean forceUpdate) {
    if (isVisiableToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
        fetchData();
        isDataInitiated = true;
        return true;
    }
    return false;
}

public LoadingPager getmLoadingPager() {
    return mLoadingPager;
}


/**
 * 創建成功視圖,交給具體子類完成

 * 返回成功視圖,正在加載數據完成之後,並且數據加載成功,我們必須告知具體的成功制圖

 * initSuccess()它是LoadingPager的同名方法,實現了一個中轉
 * 
 子類完成的,子類這個方法返回的view就是oncreateView方法中返回的view
 *
 * @return 成功視圖
 */
protected abstract View initSuccess();

/**
 * 真正加載數據,必須實現,直接抽象讓子類實現

 * loadData()調用的時候被調用

 * initData 它是LoadingPager的同名方法,實現了一個中轉
 *
 * @return 加載狀態返回
 */
protected abstract LoadResult initData();

/**
 * @param object 網絡數據json解析之後的對象
 * @return 返回成功、失敗、空
 */
public LoadResult checksState(Object object) {
    if (object == null) {
        return LoadResult.EMPTY;
    }
    //如果是對象類型 list
    if (object instanceof List) {
        if (((List) object).size() == 0) {
            return LoadResult.EMPTY;
        }
    }
    //如果對象類型是map
    if (object instanceof Map) {
        if (((Map) object).size() == 0) {
            return LoadResult.EMPTY;
        }
    }
    return LoadResult.SUCCESS;
}
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved