當(dāng)頁面加載數(shù)據(jù)失敗或者數(shù)據(jù)為空,我們應(yīng)該怎么辦繁莹?
體驗(yàn)良好的APP都會(huì)做相應(yīng)的處理檩互。
比如網(wǎng)絡(luò)異常,會(huì)顯示一個(gè)網(wǎng)絡(luò)異常頁面咨演,提示用戶去檢查網(wǎng)絡(luò)闸昨;
數(shù)據(jù)為空時(shí),出現(xiàn)一個(gè)溫馨的空頁面薄风,引導(dǎo)用戶去創(chuàng)建數(shù)據(jù)等饵较;
這些方法各大app都在使用,但是怎么發(fā)開遭赂?每一個(gè)頁面都寫一個(gè)空頁循诉、面錯(cuò)誤頁面和loading頁面嗎?那也太惡心了吧撇他。
1茄猫、每個(gè)頁面都include 一個(gè)公用的空頁面/錯(cuò)誤頁面狈蚤,當(dāng)出現(xiàn)異常的時(shí)候動(dòng)態(tài)的 visible/gone,想想都惡心划纽,因?yàn)槊總€(gè)頁面都會(huì)出現(xiàn)這種情況脆侮,而且每個(gè)頁面還需要去處理相應(yīng)的邏輯,工作量非常大勇劣,不利于代碼的整潔
2靖避、每當(dāng)出現(xiàn)異常的時(shí)候,動(dòng)態(tài)的去向當(dāng)前的頁面 addview芭毙,這樣做會(huì)有很大的局限性筋蓖,跟布局必須是相對(duì)布局,或者是幀布局退敦,而且也要處理很多次相同的邏輯
經(jīng)過一段時(shí)間的苦想粘咖,想出了下面的解決方案,打造簡(jiǎn)單靈活的支持Activity/Fragment 空頁面及錯(cuò)誤頁面:
先簡(jiǎn)單的看一下效果:
1侈百、網(wǎng)絡(luò)異常情況:
這里我做的比較簡(jiǎn)單瓮下,只是用廣播動(dòng)態(tài)的去監(jiān)聽當(dāng)前的網(wǎng)絡(luò)狀況,當(dāng)沒有網(wǎng)絡(luò)的時(shí)候钝域,通過 setcontentview 切換當(dāng)前 activity的頁面讽坏,當(dāng)有網(wǎng)絡(luò)的情況,再切換回去即可例证。
/**
* 注冊(cè)監(jiān)聽網(wǎng)絡(luò)的廣播
*/
private void registerReceiver() {
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
this.registerReceiver(myNetReceiver, filter);
}
/** * 處理廣播 */
private BroadcastReceiver myNetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
NetworkInfo wifiNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) {
Log.e("dddd","網(wǎng)絡(luò)不可以用");
//顯示網(wǎng)絡(luò)異常頁面路呜,具體方法下面贅述
showNetError(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}else {
Log.e("dddd","網(wǎng)絡(luò)可以用");
//隱藏網(wǎng)絡(luò)異常頁面,具體方法下面贅述
dimissNetError();
}
}
};
2织咧、頁面空數(shù)據(jù)情況:
當(dāng)我們請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)胀葱,數(shù)據(jù)為空的時(shí)候,顯示空面
/**
* 顯示空頁面
*/
showEmpty(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
}
});
/**
* 空頁面消失
*/
dimissEmpty();
看了上面的方法笙蒙,是不是感覺還蠻像那么回事的抵屿,下面看看是怎么實(shí)現(xiàn)的(如果有什么不好的地方,盡管提出來)
1捅位、先定義一個(gè)接口
public interface BaseView {
/**
* 展示加載框
*/
void showLoading();
/**
* 取消加載框展示
*/
void dismissLoading();
/**
* 顯示錯(cuò)誤信息
*/
void showErrorMsg(String msg);
/**
* 顯示空頁面
*/
void showEmpty(SwipeRefreshLayout.OnRefreshListener listener);
/**
* 空頁面消失轧葛,恢復(fù)之前的頁面
*/
void dimissEmpty();
/**
* 顯示網(wǎng)絡(luò)錯(cuò)誤頁面
*/
void showNetError(View.OnClickListener listener);
/**
* 網(wǎng)絡(luò)錯(cuò)誤頁面,恢復(fù)之前的頁面
*/
void dimissNetError();
}
我的做法是艇搀,這些通用的東西尿扯,通通放到baseActivity 中
/**
* 基礎(chǔ) activity
* Created by Mr.Z on 16/7/12.
*/
public abstract class BaseActivity extends AppCompatActivity implements BaseView {
/**
* 緩沖框
*/
private MyBasicDialog myBasicDialog;
/**
* 下拉刷新
*/
protected SwipeRefreshLayout mSwipeRefreshLayout;
private LayoutInflater inflater;
/**
* 當(dāng)前頁面的布局
*/
protected View layoutMain = null;
/**
* 空頁面布局
*/
protected View layout_empty = null;
/**
* 網(wǎng)絡(luò)異常布局
*/
protected View layout_net_error = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
inflater = this.getLayoutInflater();
layoutMain = inflater.inflate(setLayoutId(), null);
layout_empty = inflater.inflate(R.layout.empty_activity, null);
layout_net_error = inflater.inflate(R.layout.net_error_activity, null);
setContentView(layoutMain);
initContentView(savedInstanceState);
registerReceiver();
}
/**
* 顯示緩沖框
*/
@Override
public void showLoading() {
WaitDialog waitDialog = new WaitDialog(this);
showDialog(waitDialog);
}
/**
* 設(shè)置當(dāng)前的布局id
*
* @return
*/
public abstract int setLayoutId();
/**
* 初始化UI
*
* @param savedInstanceState
*/
protected abstract void initContentView(Bundle savedInstanceState);
/**
* 緩沖框消失
*/
@Override
public void dismissLoading() {
hideDialog();
}
/**
* 錯(cuò)誤提示
*/
@Override
public void showErrorMsg(String msg) {
Dialog alertDialog = new AlertDialog.Builder(this).
setTitle("溫馨提示").
setMessage(msg).
setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}).
create();
alertDialog.show();
}
/**
* 顯示空頁面
*/
@Override
public void showEmpty(SwipeRefreshLayout.OnRefreshListener listener) {
setContentView(layout_empty);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.mSwipeRefreshLayout);
mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);
mSwipeRefreshLayout.setOnRefreshListener(listener);
}
/**
* 空頁面消失
*/
@Override
public void dimissEmpty() {
myHandler.sendEmptyMessage(3);
}
/**
* 網(wǎng)絡(luò)異常
*/
@Override
public void showNetError(View.OnClickListener listener) {
setContentView(layout_net_error);
LinearLayout root = (LinearLayout) findViewById(R.id.netlayout);
root.setOnClickListener(listener);
}
/**
* 隱藏網(wǎng)絡(luò)異常
*/
@Override
public void dimissNetError() {
setContentView(layoutMain);
}
/**
* 顯示對(duì)話框
*
* @param myBasicDialog
*/
private void showDialog(MyBasicDialog myBasicDialog) {
this.myBasicDialog = myBasicDialog;
myHandler.sendEmptyMessage(2);
}
/**
* 隱藏對(duì)話框
*/
private void hideDialog() {
myHandler.sendEmptyMessage(1);
}
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1://隱藏對(duì)話框
DialogManager.getInstance().hideDialog();
break;
case 2://顯示對(duì)話框
DialogManager.getInstance().showDialog(myBasicDialog);
break;
case 3://刷新頁面
mSwipeRefreshLayout.removeAllViews();
setContentView(layoutMain);
mSwipeRefreshLayout.setRefreshing(false);
break;
}
}
};
/**
* 切換 fragment
*
* @param contentId
* @param fragment
*/
public void switchFragment(int contentId, BaseFragment fragment) {
getSupportFragmentManager().beginTransaction().replace(contentId, fragment).addToBackStack(null).commit();
}
/**
* 切換空 fragment
*
* @param contentId
*/
public void switchEmptyFragment(int contentId, SwipeRefreshLayout.OnRefreshListener listener) {
EmptyFragment emptyFragment = new EmptyFragment();
emptyFragment.setOnRefresh(listener);
switchFragment(contentId, emptyFragment);
}
/**
* 隱藏空 fragment
*/
public void dissMissEmptyFragment() {
getSupportFragmentManager().popBackStack();
}
/**
* 切換網(wǎng)絡(luò)異常 fragment
*
* @param contentId
*/
public void switchNetErrorFragment(int contentId, View.OnClickListener listener) {
NetErrorFragment netErrorFragment = new NetErrorFragment();
netErrorFragment.setOnRefresh(listener);
switchFragment(contentId, netErrorFragment);
}
/**
* 隱藏網(wǎng)絡(luò)異常 fragment
*/
public void disMissNetErrorFragment() {
getSupportFragmentManager().popBackStack();
}
/**
* 點(diǎn)擊鍵盤以外部分,鍵盤消失
*
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
return super.dispatchTouchEvent(ev);
}
// 必不可少焰雕,否則所有的組件都不會(huì)有TouchEvent了
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
/**
* 當(dāng)前鍵盤的顯示情況
*
* @param v
* @param event
* @return
*/
private boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] leftTop = {0, 0};
//獲取輸入框當(dāng)前的location位置
v.getLocationInWindow(leftTop);
int left = leftTop[0];
int top = leftTop[1];
int bottom = top + v.getHeight();
int right = left + v.getWidth();
if (event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom) {
// 點(diǎn)擊的是輸入框區(qū)域姜胖,保留點(diǎn)擊EditText的事件
return false;
} else {
return true;
}
}
return false;
}
/**
* 注冊(cè)監(jiān)聽網(wǎng)絡(luò)的廣播
*/
private void registerReceiver() {
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
this.registerReceiver(myNetReceiver, filter);
}
/**
* 處理廣播
*/
private BroadcastReceiver myNetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
NetworkInfo wifiNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) {
Log.e("dddd","網(wǎng)絡(luò)不可以用");
showNetError(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}else {
Log.e("dddd","網(wǎng)絡(luò)可以用");
dimissNetError();
}
}
};
}
ps:
1、空頁面中加入了SwipeRefreshLayout淀散,實(shí)現(xiàn)下拉刷新頁面右莱,并將接口暴露出來
2、網(wǎng)絡(luò)異常頁面档插,將點(diǎn)擊方法暴露出去
Github 地址.
如果覺得不錯(cuò)慢蜓,不要忘記在github上點(diǎn)??Star哦