在app開發(fā)過程中很多時候我們需要訪問網(wǎng)絡后德,訪問數(shù)據(jù)庫等,此時app將會有多種狀態(tài)抄腔,比如加載中瓢湃,加載成功,加載失敗赫蛇,沒有網(wǎng)絡等等绵患,此時如果我們使用彈出的方式告知用戶,非常不友好棍掐。之前被產(chǎn)品爸爸說有種笨重的感覺藏雏,但是笨重這么抽象你告訴我我TM該怎么理解呢?
經(jīng)過leader的暗示解答,終于知道原來他想要那種感覺掘殴,就是那種看起來不笨重的感覺赚瘦,翻譯過來就是使用多狀態(tài),那么應該怎么做呢奏寨?看到過有人封裝在BaseFragment和BaseActivity起意,但是這樣子做耦合度太高,而且看起來代碼也比較笨重病瞳,是的又回到了笨重這個話題揽咕。
效果演示
那么笨重feel是怎樣的呢?
那么一般我們應該怎么做呢套菜?
看看下面的小圖圖:
整體結構
那么它的整體結構是怎樣的呢亲善?
從上面的整體結構i圖可以知道主要有以下方法:
createView() 構造方法,這里重載了兩個逗柴,分別使用默認的view以及使用you like view
onLoad() 加載方法蛹头,顯示loadingview
onEmpty() 空數(shù)據(jù),顯示emptyView
onError() 加載出錯戏溺,顯示errorView
onNoNet() 沒有網(wǎng)絡渣蜗,顯示noNetView
onSuccess 加載成功,顯示構造方法傳入的contentView
onDestory() 資源回收
setOnRetryClick() 提供點擊重新加載的接口
使用
使用方法很簡單旷祸,根據(jù)上面的整體結構
- 構造
StatusViewManager manager = StatusViewManager.createView(Context, ContentView);
- 加載
manager.onLoad()
- 根據(jù)情況調用各種狀態(tài)
代碼實現(xiàn)
StatusViewManager
/**
* Created by AmatorLee on 2017/7/12.
*/
public class StatusViewManager extends StatusInterface implements View.OnClickListener {
private LayoutInflater mInflater;
/**
* 加載view
*/
private View mLoadView;
/**
* 錯誤view
*/
private View mErrorView;
/**
* 無數(shù)據(jù)view
*/
private View mEmptyView;
/**
* 實際view
*/
private View mContentView;
/**
* 無網(wǎng)絡鏈接時得view
*/
private View mNoNetView;
private RelativeLayout.LayoutParams mParams;
/**
* 保存狀態(tài)view的container
*/
private RelativeLayout mStatusContainer;
private Context mContext;
/**
* 避免重復添加
*/
private boolean isAddLoad, isAddEmpty, isAddNoNet, isAddError;
/**
* 可見狀態(tài)
*/
public static final int V = View.VISIBLE;
/***
* 不可見狀態(tài)
*/
public static final int G = View.GONE;
/**
* 重新加載接口
*/
private onRetryClick mOnRetryClick;
/**
* 切換到主線程改變view的狀態(tài)
*/
private Handler mMainThreadHandler;
private int empty_layout_id = -1;
private int error_layout_id = -1;
private int no_net_layout_id = -1;
private int loading_layout_id = -1;
public static final String ERROR = "error";
public static final String EMPTY = "empty";
public static final String NONET = "nonet";
public static final String LOAD = "load";
public void setOnRetryClick(onRetryClick onRetryClick) {
mOnRetryClick = onRetryClick;
}
private StatusViewManager(Context context, View contentView, int loading_layout_id, int empty_layout_id, int error_layout_id, int no_net_layout_id) {
super();
this.loading_layout_id = loading_layout_id;
this.empty_layout_id = empty_layout_id;
this.error_layout_id = error_layout_id;
this.no_net_layout_id = no_net_layout_id;
mContentView = contentView;
mMainThreadHandler = new Handler(Looper.getMainLooper());
mContext = context;
mInflater = LayoutInflater.from(context);
mParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
mParams.addRule(RelativeLayout.CENTER_IN_PARENT);
initView();
setOnClick();
initContainer();
}
private void setOnClick() {
if (mEmptyView != null)
mEmptyView.setOnClickListener(this);
if (mNoNetView != null)
mNoNetView.setOnClickListener(this);
if (mErrorView != null)
mErrorView.setOnClickListener(this);
}
public static StatusViewManager createView(Context context, View ContentView) {
return new StatusViewManager(context, ContentView, -1, -1, -1, -1);
}
public static StatusViewManager createView(Context context, View contentView, int loading_layout_id, int empty_layout_id, int error_layout_id, int no_net_layout_id) {
return new StatusViewManager(context, contentView, loading_layout_id, empty_layout_id, error_layout_id, no_net_layout_id);
}
@Override
protected void initView() {
if (loading_layout_id == -1) {
loading_layout_id = R.layout.layout_loading;
}
if (empty_layout_id == -1) {
empty_layout_id = R.layout.layout_empty;
}
if (error_layout_id == -1) {
error_layout_id = R.layout.layout_error;
}
if (no_net_layout_id == -1) {
no_net_layout_id = R.layout.layout_no_net;
}
try {
mLoadView = mInflater.inflate(loading_layout_id, null);
mLoadView.setTag(LOAD);
mErrorView = mInflater.inflate(error_layout_id, null);
mErrorView.setTag(ERROR);
mEmptyView = mInflater.inflate(empty_layout_id, null);
mEmptyView.setTag(EMPTY);
mNoNetView = mInflater.inflate(no_net_layout_id, null);
mNoNetView.setTag(NONET);
} finally {
mInflater = null;
}
}
@Override
public void initContainer() {
mStatusContainer = new RelativeLayout(mContext);
mStatusContainer.setLayoutParams(mParams);
ViewGroup parent = (ViewGroup) mContentView.getParent();
parent.addView(mStatusContainer);
}
@Override
public void onLoad() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (mLoadView != null && !isAddLoad) {
isAddLoad = true;
mStatusContainer.addView(mLoadView, mParams);
}
show(STATUS.LOADING);
}
});
}
private void show(STATUS result) {
switch (result) {
case SUCCESS:
changeVisiable(V, G, G, G, G);
break;
case LOADING:
changeVisiable(G, V, G, G, G);
break;
case NONET:
changeVisiable(G, G, G, G, V);
break;
case ERROR:
changeVisiable(G, G, G, V, G);
break;
case EMPTY:
changeVisiable(G, G, V, G, G);
break;
}
}
private void changeVisiable(final int contentStatus, final int loadStatus, final int emptyStatus, final int errorStatus, final int nonetStatus) {
if (mContentView != null) {
mContentView.setVisibility(contentStatus);
}
if (mLoadView != null) {
mLoadView.setVisibility(loadStatus);
}
if (mEmptyView != null) {
mEmptyView.setVisibility(emptyStatus);
}
if (mNoNetView != null) {
mNoNetView.setVisibility(nonetStatus);
}
if (mErrorView != null) {
mErrorView.setVisibility(errorStatus);
}
}
@Override
public void onSuccess() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
show(STATUS.SUCCESS);
}
});
}
@Override
public void onNoNet() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isAddNoNet && mNoNetView != null) {
mStatusContainer.addView(mNoNetView, mParams);
isAddNoNet = true;
}
show(STATUS.NONET);
}
});
}
@Override
public void onError() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isAddError && mErrorView != null) {
mStatusContainer.addView(mErrorView, mParams);
isAddError = true;
}
show(STATUS.ERROR);
}
});
}
@Override
public void onEmpty() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isAddEmpty && mEmptyView != null) {
mStatusContainer.addView(mEmptyView, mParams);
isAddEmpty = true;
}
show(STATUS.EMPTY);
}
});
}
@Override
public void onClick(View view) {
if (mOnRetryClick != null) {
mOnRetryClick.onRetryLoad();
}
}
public enum STATUS {
LOADING,
EMPTY,
ERROR,
SUCCESS,
NONET
}
@Override
public void onDestory() {
isAddNoNet = false;
isAddEmpty = false;
isAddLoad = false;
isAddError = false;
mContext = null;
if (mLoadView != null) {
mLoadView = null;
}
if (mContentView != null) {
mContentView = null;
}
if (mEmptyView != null) {
mEmptyView = null;
}
if (mErrorView != null) {
mErrorView = null;
}
if (mNoNetView != null) {
mNoNetView = null;
}
if (mParams != null) {
mParams = null;
}
for (int i = 0; i < mStatusContainer.getChildCount(); i++) {
mStatusContainer.removeViewAt(i);
}
mStatusContainer = null;
}
interface onRetryClick {
void onRetryLoad();
}
}```
#####StatusInterface
/**
- Created by AmatorLee on 2017/7/12.
*/
public abstract class StatusInterface {
protected abstract void initView();
protected abstract void initContainer();
protected abstract void onLoad();
protected abstract void onSuccess();
protected abstract void onNoNet();
protected abstract void onError();
protected abstract void onEmpty();
protected abstract void onDestory();
}你可能會問為什么要提供一個
StatusInterface```,但是我不告訴你耕拷。
總結
現(xiàn)在流行的直播平臺大都是這個小技巧,雖然簡單但是常用托享,所有自己簡單的寫一下骚烧,如果你發(fā)現(xiàn)有bug,盡情反饋闰围,同時我也會自我完善止潘。
最后,provide a gayhub demo