編輯:關於Android編程
通常都知道,android中一個頁面的加載,無非三種狀態:
加載中 加載成功 加載失敗當然,如果從網絡獲取數據,可能會出現數據為空的情況。這裡也要考慮進去
具體看下截圖
這裡可以抽下共有的方法。
/** * 描述: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)SharePreferences所生成的
一.問題引入ListView控件:給Item綁定了點擊事件,卻點擊無效。二.解決方案ListView使用了自定義布局文件,在布局文件中有button等控件時,這些控件獲取
主要實現辦法:動態加載各級下拉值的適配器在監聽本級下拉框,當本級下拉框的選中值改變時,隨之修改下級的適配器的綁定值 &
前言:經過昨天的學習,感覺對socket越來越熟悉了,但還是得多寫寫。業精於勤荒於嬉,行成於思毀於隨!今天我寫了一個與項目稍微接近的一個小程序。對socket越來越深入了