在一个成熟的安卓项目中,我们需要时刻关注app的运行状态,并且根据状态显示相应的UI界面,必须网络中断,内容为空等等。因此一个好的UILoader界面非常重要,下面通过一个简单的例子定义一个UILoader
一、UILoader是什么?
1、UILoader是app运行状态的结果集,在数据流异常的时候可以做到及时展示,通过实现里面的方法,也可以自定义实现相关的调用ui显现。
一般有以下状态:网络错误(点击重试),内容为空,正在加载,成功加载等状态,如下图
fragmet_error_view
fragmet_empty_view
fragmet_loading_view
二、UILoaded定义
1.UILoaded
代码如下(示例):
public abstract class UILoader extends FrameLayout {
private View mLoadingView;
private View mSuccessView;
private View mNetWorkErrorView;
private View mEmptyView;
private OnRetryClickListener mOnRetryClickListener=null;
public enum UIState{
//定义4个状态 加载中,成功时,网络错误时,内容为空时
LOADING,SUCCESS,NETWORK_ERROR,EMPTY,NONE
}
//当前状态
public UIState mCurrentStatus=UIState.NONE;
//为了方便,统一在同一个构造方法中进行初始化
public UILoader(@NonNull Context context) {
this(context,null);
}
public UILoader(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public UILoader(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//init UI
private void init() {
switchUIByCurrentStates();
}
//先初始化载入相应的状态View,并根据状态设置是否可以可见
private void switchUIByCurrentStates() {
//Loading
if(mLoadingView==null) {
mLoadingView = getLoadingView();
addView(mLoadingView);
}
// change visibility by states
mLoadingView.setVisibility(mCurrentStatus==UIState.LOADING ? VISIBLE : GONE);
//Success
if(mSuccessView==null) {
mSuccessView = getSuccessView(this);
addView(mSuccessView);
}
// change visibility by states
mSuccessView.setVisibility(mCurrentStatus == UIState.SUCCESS ? VISIBLE : GONE);
//netWork worring
if(mNetWorkErrorView ==null) {
mNetWorkErrorView = getNetWorkErrorView();
addView(mNetWorkErrorView);
}
// change visibility by states
mNetWorkErrorView .setVisibility(mCurrentStatus==UIState.NETWORK_ERROR ? VISIBLE : GONE);
//date is null
if(mEmptyView ==null) {
mEmptyView = getEmptyView();
addView(mEmptyView);
}
// change visibility by states
mEmptyView .setVisibility(mCurrentStatus==UIState.EMPTY ? VISIBLE : GONE);
}
//当状态改变的时候,也要及时变更ui的状态
public void updateStatus(UIState status){
mCurrentStatus=status;
//update ui in main thread
BaseApplication.getsHandler().post(new Runnable() {
@Override
public void run() {
switchUIByCurrentStates();
}
});
}
//载入内容为空的View,具体的ui可以自定义,这里设置为fragmet_empty_view
protected View getEmptyView() {
return LayoutInflater.from(getContext()).inflate(R.layout.fragmet_empty_view,this,false);
}
//载入网络错误的View,具体的ui可以自定义,这里为fragmet_error_view
private View getNetWorkErrorView() {
View netWorkError=LayoutInflater.from(getContext()).inflate(R.layout.fragmet_error_view,this,false);
netWorkError.findViewById(R.id.network_error_icon).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
//reflash
if (mOnRetryClickListener != null) {
mOnRetryClickListener.onRetryClick();
}
}
});
return netWorkError;
}
//由于成功时的状态是多变的,我门先定义为抽象方法,由调用者去实现相关的ui显示
protected abstract View getSuccessView(ViewGroup viewGroup);
//载入正在加载的View,具体的ui可以自定义,这里为fragmet_loading_view
private View getLoadingView() {
return LayoutInflater.from(getContext()).inflate(R.layout.fragmet_loading_view,this,false);
}
//网络错误时淫才可以点击重试,所以定义如下的接口,由调用者去实现相关的点击方法
public void setOnRetryClickListener(OnRetryClickListener listner){
this.mOnRetryClickListener=listner;
}
public interface OnRetryClickListener{
void onRetryClick();
}
}
2.运用UILoader
代码如下(示例):
if (mUiLoader == null) {
mUiLoader = new UILoader(this) {
// 实现成功时的View
@Override
protected View getSuccessView(ViewGroup viewGroup) {
return createSuccessView(viewGroup);
}
};
mDetailListContainer.removeAllViews();
//为了接下来的状态改变,我们应该移除已经载入的uiLoader的子View
//mDetailListContainer为调用uiload的容器
mDetailListContainer.addView(mUiLoader);
mUiLoader.setOnRetryClickListener(DetailActivity.this);
}
最后当需要改变ui的状态的时候,直接调用
UiLoader.updateStatus(UILoader.UIState.状态码);
注意,如果需要在网络中断的时候点击重试,应该还要设置setOnRetryClickListener方法。并实OnRetryClickListener的方法细节
总结
通过UILoader我们可以做到重构多余的UI更改代码,通过实现getSuccessView方法,去自定义处理成功界面的显现,做到一码多用。