編輯:關於Android編程
通常都知道,android中一個頁面的加載,無非三種狀態:
加載中 加載成功 加載失敗當然,如果從網絡獲取數據,可能會出現數據為空的情況。這裡也要考慮進去
具體看下截圖




這裡可以抽下共有的方法。
/**
* 描述:LoadingPager 不會在xml中使用,所以只實現context參數的構造
* 作者:Marc on 2016/7/7 09:27
* 郵箱:aliali_ha@yeah.net
*/
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
* 郵箱:aliali_ha@yeah.net
*/
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;
}
}
(Android review)SharePreferences的使用
典型應用場合: 進入某一界面以後,顯示默認值(其實這個也可以通過直接在布局文件中指定) 基本點: 1)SharePreferences所生成的
Android開發:ListView控件:給Item綁定了點擊事件,卻點擊無效
一.問題引入ListView控件:給Item綁定了點擊事件,卻點擊無效。二.解決方案ListView使用了自定義布局文件,在布局文件中有button等控件時,這些控件獲取
Android實現三級聯動下拉框 下拉列表spinner的實例代碼
主要實現辦法:動態加載各級下拉值的適配器在監聽本級下拉框,當本級下拉框的選中值改變時,隨之修改下級的適配器的綁定值 &
Java Socket 通信 (三)
前言:經過昨天的學習,感覺對socket越來越熟悉了,但還是得多寫寫。業精於勤荒於嬉,行成於思毀於隨!今天我寫了一個與項目稍微接近的一個小程序。對socket越來越深入了