問題場景
Android開發(fā)中大部分頁面都包含如下邏輯:
- 進(jìn)入頁面钞螟,加載網(wǎng)絡(luò)數(shù)據(jù)勤众,顯示加載頁面
- 加載完成后论寨,有以下幾種情況:
- 正常返回赖临,有有效數(shù)據(jù)胞锰,顯示“有效界面”
- 正常返回,有效數(shù)據(jù)為空兢榨,顯示“空數(shù)據(jù)界面”
- 正常返回嗅榕,服務(wù)器判定輸入?yún)?shù)異常顺饮,顯示“參數(shù)異常界面”,比如“用戶登錄失效”等凌那,直接跳轉(zhuǎn)相應(yīng)的頁面
- 異常返回兼雄,網(wǎng)絡(luò)超時,無法訪問服務(wù)器等狀態(tài)案怯,顯示“加載失敗頁面”
- 無法訪問網(wǎng)絡(luò)君旦,顯示“無法訪問網(wǎng)絡(luò)界面”。
怎么解決呢嘲碱?
原本想各個界面由NetFragment提供接口進(jìn)行設(shè)置金砍,后來考慮Android的界面基本xml繪制,透過id與代碼綁定麦锯。那不如采用“約定優(yōu)于配置原則”恕稠,直接規(guī)定好那些id標(biāo)識哪些界面,NetFragment里面根據(jù)相應(yīng)的id去尋找界面即可扶欣。所以最后約定id名稱如下:
- 加載界面 R.id.net_progress
- 有效界面 R.id.net_result
- 空數(shù)據(jù)界面 R.id.net_no_result
- 參數(shù)異常界面 R.id.net_error
- 加載失敗頁面 R.id.net_fail
- 無法訪問網(wǎng)絡(luò)界面 R.id.net_cannot_access
基于SOLID原則中的S——單一責(zé)任原則(The Single Responsibility Principle)鹅巍,各個界面的點擊、觸摸都由各自處理料祠,NetFragment只負(fù)責(zé)加載數(shù)據(jù)骆捧、控制各類界面顯示隱藏,至于下拉刷新髓绽、上拉加載下一頁數(shù)據(jù)等操作都不在此類里面內(nèi)進(jìn)行管理敛苇。
最后產(chǎn)生的代碼——NetFragment.java
package lib;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.freetek.deepsea.R;
import panda.android.lib.base.control.SimpleSafeTask;
import panda.android.lib.base.model.ListNetResultInfo;
import panda.android.lib.base.model.NetResultInfo;
import panda.android.lib.base.model.net.BaseRepositoryCollection;
import panda.android.lib.base.ui.fragment.BaseFragment;
import panda.android.lib.base.util.DevUtil;
import panda.android.lib.base.util.Log;
/**
* 加載網(wǎng)頁數(shù)據(jù)的通用模型,包含 進(jìn)度條控制顺呕、結(jié)果顯示控制枫攀。
*
* @param <T>
* @author shitianci
*/
public abstract class NetFragment<T extends NetResultInfo> extends BaseFragment {
private static final String TAG = NetFragment.class.getSimpleName();
protected View mViewProgress = null; //加載界面
protected View mViewResult = null; //有效界面
protected View mViewNoResult = null; //空數(shù)據(jù)界面
protected View mViewError = null; //參數(shù)異常界面
protected View mViewFail = null; //加載失敗頁面
protected View mViewCannotAccess = null; //無法訪問網(wǎng)絡(luò)
protected SimpleSafeTask<T> netTask = null;
private View[] mViewArray;
private int[] mViewArrayID = new int[]{
R.id.net_progress, //加載界面
R.id.net_result, //有效界面
R.id.net_no_result, //空數(shù)據(jù)界面
R.id.net_error, //參數(shù)異常界面
R.id.net_fail, //加載失敗頁面
R.id.net_cannot_access}; //無法訪問網(wǎng)絡(luò)
//todo 這些數(shù)據(jù)需要放到xml里面進(jìn)行管理
private String[] mViewToastString = new String[]{
"正在加載中", //加載界面
"加載到有效數(shù)據(jù)了", //有效界面
"加載數(shù)據(jù)為空", //空數(shù)據(jù)界面
"參數(shù)異常", //參數(shù)異常界面
"無法訪問服務(wù)器", //加載失敗頁面
"無法訪問網(wǎng)絡(luò)"}; //無法訪問網(wǎng)絡(luò)
@Override
public int getLayoutId() {
return R.layout.panda_fragment_net;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View createdView = super.onCreateView(inflater, container,
savedInstanceState);
mViewProgress = createdView.findViewById(R.id.net_progress);
mViewResult = createdView.findViewById(R.id.net_result);
mViewNoResult = createdView.findViewById(R.id.net_no_result);
mViewError = createdView.findViewById(R.id.net_error);
mViewFail = createdView.findViewById(R.id.net_fail);
mViewCannotAccess = createdView.findViewById(R.id.net_cannot_access);
mViewArray = new View[]{mViewProgress, mViewResult, mViewNoResult, mViewError, mViewFail, mViewCannotAccess};
return createdView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
loadNetData(false);
}
boolean loadingNetData = false;
public void loadNetData() {
loadNetData(false);
}
public void loadNetData(final boolean useSecondModel) {
Log.d(TAG, "loadNetData, loadingNetData = " + loadingNetData);
if (loadingNetData) {
return;
}
if (!BaseRepositoryCollection.tryToDetectNetwork(getActivity())) {
showOnlyView(R.id.net_cannot_access, useSecondModel);
return;
}
netTask = new SimpleSafeTask<T>(getActivity()) {
protected void onPreExecuteSafely() throws Exception {
loadingNetData = true;
showOnlyView(R.id.net_progress, useSecondModel);
onPreloadNetData(useSecondModel);
}
@Override
protected T doInBackgroundSafely() throws Exception {
T result = onDoInBackgroundSafely();
return result;
}
@Override
protected void onPostExecuteSafely(T result, Exception e) {
onPostloadNetData(useSecondModel);
super.onPostExecuteSafely(result, e);
loadingNetData = false;
if (e != null || result == null) {
showOnlyView(R.id.net_fail, useSecondModel);
return;
}
if (result.getRespCode() != NetResultInfo.RETURN_CODE_000000) {
showOnlyView(R.id.net_error, useSecondModel);
return;
}
if (result instanceof ListNetResultInfo && ((ListNetResultInfo) result).getList().size() == 0) {
showOnlyView(R.id.net_no_result, useSecondModel);
return;
}
showOnlyView(R.id.net_result, useSecondModel);
onDisplayResult(result);
}
protected void onCancelled() {
loadingNetData = false;
showOnlyView(R.id.net_fail, useSecondModel);
}
};
netTask.execute();
return;
}
/**
* -------------------------
* START: 最重要的流程方法
* -------------------------
*/
/**
* 開始加載網(wǎng)絡(luò)數(shù)據(jù)
* @param useSecondModel
*/
public void onPreloadNetData(boolean useSecondModel) {
}
/**
* 加載后臺數(shù)據(jù)
*
* @return
*/
protected abstract T onDoInBackgroundSafely();
/**
* 顯示后臺數(shù)據(jù)
*
* @param result
*/
protected abstract void onDisplayResult(T result);
/**
* 網(wǎng)絡(luò)數(shù)據(jù)加載結(jié)束
* @param useSecondModel
*/
public void onPostloadNetData(boolean useSecondModel) {
}
/**
* -------------------------
* END
* -------------------------
*/
/**
* -------------------------
* START: 純粹的界面展示控制,不推薦外部調(diào)用株茶、重寫
* -------------------------
*/
/**
* 顯示指定的View来涨,剩下的界面都隱藏。
*
* @param useSecondModel 是否啟用第二次模式启盛,在加載第2……n次數(shù)據(jù)時蹦掐,無需切換其它界面,采用Toast顯示信息即可僵闯。
*/
protected void showOnlyView(int viewId, boolean useSecondModel) {
int i = 0;
for (View v : mViewArray) {
i++;
if (v == null) {
continue;
} else if (v.getId() == viewId) {
Log.d(TAG, "showOnlyView, i = " + i);
if (useSecondModel && (viewId != R.id.net_progress || viewId != R.id.net_result)) {
DevUtil.showInfo(getActivity(), mViewToastString[i-1]);
} else {
v.setVisibility(View.VISIBLE);
}
} else {
v.setVisibility(View.GONE);
}
}
}
protected void showProgress() {
Log.d(TAG, "showProgress, mViewProgress = " + mViewProgress);
if (mViewProgress != null) {
mViewProgress.setVisibility(View.VISIBLE);
}
}
protected void hiddenProgress() {
Log.d(TAG, "hiddenProgress, mViewProgress = " + mViewProgress);
if (mViewProgress != null) {
mViewProgress.setVisibility(View.GONE);
}
}
// protected void showResult() {
// Log.d(TAG, "showResult");
// if (mViewResult != null) {
// mViewResult.setVisibility(View.VISIBLE);
// }
// }
//
// protected void hiddenResult() {
// Log.d(TAG, "hiddenResult");
// if (mViewResult != null) {
// mViewResult.setVisibility(View.GONE);
// }
// }
//
// protected void showNoResult() {
// Log.d(TAG, "showNoResult");
// if (mViewNoResult != null) {
// mViewNoResult.setVisibility(View.VISIBLE);
// }
// }
//
// protected void hiddenNoResult() {
// Log.d(TAG, "hiddenNoResult");
// if (mViewNoResult != null) {
// mViewNoResult.setVisibility(View.GONE);
// }
// }
//
// public void showError() {
// Log.d(TAG, "showNetErrResult");
// if (mViewError != null) {
// mViewError.setVisibility(View.VISIBLE);
// }
// }
//
// private void hiddenError() {
// if (mViewError != null) {
// mViewError.setVisibility(View.GONE);
// }
// }
//
// public void showFail() {
// Log.d(TAG, "showFail");
// if (mViewFail != null) {
// mViewFail.setVisibility(View.VISIBLE);
// }
// }
//
// public void hiddenFail() {
// Log.d(TAG, "hiddenFail");
// if (mViewFail != null) {
// mViewFail.setVisibility(View.GONE);
// }
// }
//
// public void showCannotAccess() {
// if (mViewCannotAccess != null) {
// mViewCannotAccess.setVisibility(View.VISIBLE);
// }
// }
//
// public void hiddenCannotAccess() {
// if (mViewCannotAccess != null) {
// mViewCannotAccess.setVisibility(View.GONE);
// }
// }
/**
* -------------------------
* END
* -------------------------
*/
}
后續(xù)拓展
可以從開發(fā)者使用角度考慮笤闯,內(nèi)置一系列子類,達(dá)到各種場景中“One Step”集成的效果棍厂。比如默認(rèn)效果為:
- 加載界面:彈出一個透明背景的加載框
- 有效界面:支持 下拉刷新颗味、上拉加載下一頁
- 空數(shù)據(jù)界面:支持圖文格式
- 參數(shù)異常界面:采用Toast提示
- 加載失敗頁面:提醒用戶網(wǎng)速過慢,建議切換網(wǎng)絡(luò)
- 無法訪問網(wǎng)絡(luò)界面:提醒用戶打開網(wǎng)絡(luò)
Panda
2016-06-03