基类LoadintPager(加载三种状态)
通常都知道,android中一个页面的加载,无非三种状态:
- 加载中
- 加载成功
- 加载失败
当然,如果从网络获取数据,可能会出现数据为空的情况。这里也要考虑进去
具体看下截图
####失败
加载成功,这里界面随意弄的textview
空
加载中
这里可以抽下共有的方法。
/**
* 描述: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的布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include layout="@layout/toolbar" /> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"/> </LinearLayout>
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;
}
/**
* 创建成功视图,交给具体子类完成<br>
* 返回成功视图,正在加载数据完成之后,并且数据加载成功,我们必须告知具体的成功制图<br>
* initSuccess()它是LoadingPager的同名方法,实现了一个中转
* <br> 子类完成的,子类这个方法返回的view就是oncreateView方法中返回的view
*
* @return 成功视图
*/
protected abstract View initSuccess();
/**
* 真正加载数据,必须实现,直接抽象让子类实现<br>
* loadData()调用的时候被调用<br>
* 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;
}
}