本文共 6104 字,大约阅读时间需要 20 分钟。
在使用paging的过程中,使用起来是很方便,但也发现一些问题,比如往下滑的时候,没有加载的提示(数据正在加载中),这个时候就需要我们去处理了,数据加载可能是成功了,可能是失败了,也可能是全部加载完成了,加载过程中还有加载的结果都是需要一个友好的提示的,我们看到好多APP应用都是在item底部会有一个友好的提示,所有这边文章就是来实现如何在底部添加一个友好提示的item,数据加载成功后会自动消失。
加载数据可以分为加载过程中,加载成功,加载失败,数据全部加载完成,如果还有其他状态可自行添加,根据这些状态就可以定义一个枚举类来描述这几种情况:
public enum RequestDataState { //加载过程中 LOADING, //加载成功 SUCCESS, //加载失败 FAIL, //全部加载完成 COMPLETE}
对于paging来说,数据加载的功能全部交给了DataSource,DataSource有三个子类,我们可以根据不同的需求去实现对应的子类,这里以PageKeyedDataSource为例进行说明,其他的类似,为了处理加载数据的几种状态并且通用性强,可以将这个功能抽象出来,之后要同步加载状态的全部去实现这个类就可以了,这个还比较简单,类的定义如下:
public abstract class PageKeyedLoadDataSourceextends PageKeyedDataSource { //存储请求数据后的状态 private MutableLiveData netDataStateLiveData = new MutableLiveData<>(); public MutableLiveData getNetDataStateLiveData() { return netDataStateLiveData; } @Override public void loadAfter(@NonNull LoadParams params, @NonNull LoadCallback callback) { updateNetState(RequestDataState.LOADING); RequestDataState requestDataState = loadAfter1(params, callback); //加载数据失败后,为下次重试加载提供参数 if (requestDataState == RequestDataState.FAIL) { this.params = params; this.callback = callback; } updateNetState(requestDataState); } private LoadParams params; private LoadCallback callback; //数据加载失败后可以尝试重新进行加载 public void retryAfter(){ loadAfter(params,callback); } private void updateNetState(RequestDataState state) { netDataStateLiveData.postValue(state); } /** * @param params * @param callback * @return true加载数据成功 false加载数据失败 */ public abstract RequestDataState loadAfter1(@NonNull LoadParams params, @NonNull LoadCallback callback);}
这里提供了一个抽象方法loadAfter1(),返回请求数据的状态就好,这样封装好后,其他使用都是一样的,所以这里还是比较方便的,接下来才是重点。
对于数据显示,自然想到的就是PagedListAdapter了,这里就是通过它来显示加载状态的,问题又来了,如何才能解耦呢?就是再次封装下PagedListAdapter,处理对请求数据状态的显示,如下:
public abstract class PagedListLoadAdapterextends PagedListAdapter { //定义加载数据显示的几种状态 private static final int TYPE_LOAD_LOADING = 1002; private static final int TYPE_LOAD_ALL_COMPLETE = 1003; private static final int TYPE_LOAD_FAIL = 1004; //当前请求数据的状态 private RequestDataState state; private LifecycleOwner owner; PagedListLoadAdapter(@NonNull DiffUtil.ItemCallback diffCallback, LifecycleOwner owner) { super(diffCallback); this.owner = owner; } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) { //这里加载过程中、加载失败、加载全部完成使用的是同一个布局,可根据需要自行定义 if (type == TYPE_LOAD_LOADING || type == TYPE_LOAD_ALL_COMPLETE || type == TYPE_LOAD_FAIL) { View inflate = View.inflate(viewGroup.getContext(), R.layout.item_load_more, null); return new LoadingViewHolder(inflate); } return onCreateViewHolder1(viewGroup, type); } public abstract VH onCreateViewHolder1(@NonNull ViewGroup viewGroup, int type); @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { //根据加载状态对item的提示的处理 if (getItemViewType(position) == TYPE_LOAD_LOADING) { ((LoadingViewHolder) viewHolder).bindTo("正在加载数据,请稍候..."); return; } if (getItemViewType(position) == TYPE_LOAD_ALL_COMPLETE) { ((LoadingViewHolder) viewHolder).bindTo("所有数据已全部加载完成"); return; } if (getItemViewType(position) == TYPE_LOAD_FAIL) { ((LoadingViewHolder) viewHolder).bindTo("加载数据失败"); return; } onBindViewHolder1(viewHolder, position); } public abstract void onBindViewHolder1(@NonNull RecyclerView.ViewHolder viewHolder, int position); @Override public int getItemCount() { if (state == RequestDataState.LOADING || state == RequestDataState.COMPLETE || state == RequestDataState.FAIL) { return super.getItemCount() + 1; } return super.getItemCount(); } @Override public int getItemViewType(int position) { if (position == getItemCount() - 1 && (state == RequestDataState.LOADING)) return TYPE_LOAD_LOADING; if (position == getItemCount() - 1 && (state == RequestDataState.FAIL)) return TYPE_LOAD_FAIL; if (position == getItemCount() - 1 && (state == RequestDataState.COMPLETE)) { View view = new TextView((Activity) owner); //3秒后不显示加载完成的提示 view.postDelayed(() -> { PagedListLoadAdapter.this.state = RequestDataState.SUCCESS; notifyItemChanged(getItemCount()); }, 3000); return TYPE_LOAD_ALL_COMPLETE; } return super.getItemViewType(position); } @Override public void onCurrentListChanged(@Nullable PagedList currentList) { super.onCurrentListChanged(currentList); PagedList pagedList = getCurrentList(); if (null == pagedList) { return; } DataSource dataSource = pagedList.getDataSource(); if (dataSource instanceof PageKeyedLoadDataSource) { MutableLiveData netDataStateLiveData = ((PageKeyedLoadDataSource) dataSource).getNetDataStateLiveData(); //对加载数据状态进行监听 netDataStateLiveData.observe(owner, this::setNetState); } } public void setNetState(RequestDataState state) { this.state = state; notifyItemChanged(getItemCount()); } private class LoadingViewHolder extends RecyclerView.ViewHolder { private TextView loadView; public LoadingViewHolder(@NonNull View itemView) { super(itemView); loadView = itemView.findViewById(R.id.load_msg); } public void bindTo(String s) { loadView.setText(s); } }}
到这就算是完成了,其他所有的操作所有的和正常使用paging是一样的,只是继承的类换成是上面的PageKeyedLoadDataSource和PagedListLoadAdapter,这里需要注意PagedListLoadAdapter中定义的加载布局需要我们去定义,这样做完后,网络加载数据的提示就会自动完成。如果想要实现下拉刷新,可以使用android原生的SwipeRefreshLayout,同时需要替换掉PagedList,也就是重新在创建一个LivePagedListBuilder就ok了。
转载地址:http://mwhai.baihongyu.com/