上一篇主要介绍了Paging加载库的主要组件,以及组件之间的工作方式,不是很清楚的可以移步上一篇
Jetpack插件化学习之AndroidX Paging 大数据列表加载库一
本篇主要介绍Paging库如何在项目中使用。
开篇之前,本文的数据来源以及demo代码的书写参考了这位大佬的文章。
使用Paging Library获取网络数据
本篇也是直接加载的网络数据。
首先在项目中添加Paging库依赖
// androidx paging
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"
implementation "androidx.paging:paging-runtime:2.1.0-alpha01"
依赖中看到有AndoridX的依赖。关于AndoridX的介绍以及Android到AndroidX的升级
接下来按照Paging的组件,依次创建
初始化一个PositionalDataSource对象并实现相关方法。loadInitial、loadRange。
public class PagingItemDataViewModel extends AndroidViewModel {
public static final int CONTENT_LENGTH = 20;
public static final int FIRST_PAGE = 1;
private int mPage = FIRST_PAGE;
// final List resultBeans = new ArrayList<>();
private LiveData> mLiveData;
public PagingItemDataViewModel(@NonNull Application application) {
super(application);
}
public LiveData> getmLiveData() {
initPageList();
return mLiveData;
}
private void initPageList() {
final PositionalDataSource positionalDataSource = new PositionalDataSource() {
private int computeCount() {
//这里的实际计数代码
return CONTENT_LENGTH;
}
/**
* 网络请求耗时操作
* @param onHttpRequestListener 网络请求成功的回调
* @param page 加载到第几页
*/
private void loadRangeInternal(final OnHttpRequestListener onHttpRequestListener, int page) {
//这里的实际加载代码
ManageHttp.getWelfare1(new BaseOnResponseCallBack>(List.class) {
@Override
public void onNext(List data, int IDUrl, boolean isCache) {
onHttpRequestListener.onNext(data, IDUrl, isCache);
}
@Override
public void onStart(int IDUrl, boolean isCache) {
}
@Override
public void onCompleted(int IDUrl, boolean isCache) {
}
@Override
public void onError(Throwable e, int IDUrl, boolean isCache) {
}
}, page);
// return resultBeans;
}
@Override
public void loadInitial(@NonNull LoadInitialParams params, @NonNull final LoadInitialCallback callback) {
// 计算一页显示的条目
final int totalCount = computeCount();
// 计算显示到第几条数据
final int position = computeInitialLoadPosition(params, totalCount);
final int loadSize = computeInitialLoadSize(params, position, totalCount);
//初次初始化
loadRangeInternal(new OnHttpRequestListener() {
@Override
public void onStart(int IDUrl, boolean isCache) {
}
@Override
public void onNext(Object data, int IDUrl, boolean isCache) {
// resultBeans.addAll((Collection extends GankData>) data);
gankData = (List) data;
callback.onResult((List) data, position, totalCount);
}
@Override
public void onCompleted(int IDUrl, boolean isCache) {
}
@Override
public void onError(Throwable e, int IDUrl, boolean isCache) {
}
}, mPage);
}
List gankData = new ArrayList<>();
@Override
public void loadRange(@NonNull LoadRangeParams params, @NonNull final LoadRangeCallback callback) {
LogUtils.d("PagingItemDataViewModel", "loadRange", "params->=" + params.loadSize, "params->=" + params.startPosition);
// 每次加载到翻页条目,page增量
mPage++;
loadRangeInternal(new OnHttpRequestListener() {
@Override
public void onStart(int IDUrl, boolean isCache) {
}
@Override
public void onNext(Object data, int IDUrl, boolean isCache) {
// resultBeans.addAll((Collection extends GankData>) data);
gankData = (List) data;
// 回调到provider中
callback.onResult((List) data);
}
@Override
public void onCompleted(int IDUrl, boolean isCache) {
}
@Override
public void onError(Throwable e, int IDUrl, boolean isCache) {
}
}, mPage);
}
};
// 构建LiveData
mLiveData = new LivePagedListBuilder(new PageDataSourceFactory(positionalDataSource)
, new PagedList.Config.Builder().setPageSize(CONTENT_LENGTH)
.setPrefetchDistance(CONTENT_LENGTH)
.setEnablePlaceholders(false).setInitialLoadSizeHint(CONTENT_LENGTH)
.build()).build();
}
}
为了使项目的结构更加清晰,将此处的业务逻辑放到ViewModel层。
computeCount:方法用来初始化每一页所展示的数据。
private int computeCount() {
//这里的实际计数代码
return CONTENT_LENGTH;
}
loadRangeInternal:从网络加载数据的方法。
第一个参数onHttpRequestListener网络请求成功的回调接口,page为加载到第几页。
private void loadRangeInternal(final OnHttpRequestListener onHttpRequestListener, int page) ;
****
loadInitial:进行第一次页面加载时候的数据加载。
// 计算一页显示的条目
final int totalCount = computeCount();
// 计算显示到第几条数据
final int position = computeInitialLoadPosition(params, totalCount);
final int loadSize = computeInitialLoadSize(params, position, totalCount);
第一次数据加载完成之后,要把上述的几个变量回调出去,通知当前加载的数据条目数,以及每一页需要加载的条目数。
callback.onResult((List) data, position, totalCount);
loadRange:滑动列表时候触发数据的请求,并将数据回调出去。
public void loadRange(@NonNull LoadRangeParams params, @NonNull final LoadRangeCallback callback)
LoadRangeParams :包含当前加载的位置position、下一页加载的长度count
LoadRangeCallback:将数据回调给界面使用callback.onResult
LivePagedListProvider通过构造方法将PagedList与DataSource联系在一起。
mLiveData = new LivePagedListBuilder(new PageDataSourceFactory(positionalDataSource)
, new PagedList.Config.Builder().setPageSize(CONTENT_LENGTH)
.setPrefetchDistance(CONTENT_LENGTH)
.setEnablePlaceholders(false).setInitialLoadSizeHint(CONTENT_LENGTH)
.build()).build();
mLiveData是一个实现了观察者模式的对象。使用该对象post的方法可以将获取的数据返回到UI层,供RecycleView展示。
使用到的DataSource创建类
public class PageDataSourceFactory extends DataSource.Factory {
public PositionalDataSource mPositionalDataSource;
public PageDataSourceFactory(PositionalDataSource positionalDataSource) {
this.mPositionalDataSource =positionalDataSource;
}
@Override
public DataSource create() {
return mPositionalDataSource;
}
}
至此,我们完成了数据的分页逻辑已经完成。回头来看一下里面的代码,主要有loadInitial、loadRange这两个方法。以及初始化LiveData的过程。
接下来,我们看一下在Activity中如何获取数据。
class PagingActivity : BaseMvpActivity(), Contract.IView {
override fun initTitle() {
}
var adapter: MyAdapter? = null
var pagingItemDataViewModel: PagingItemDataViewModel? = null
override val layoutViewID: Int
get() = R.layout.activity_main_paging
override fun initPresenter(): MainPresenter {
return MainPresenter()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pagingItemDataViewModel = ViewModelProviders.of(this).get(PagingItemDataViewModel::class.java)
adapter = MyAdapter(object : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: GankData, newItem: GankData): Boolean {
return oldItem._id.equals(newItem._id)
}
override fun areContentsTheSame(oldItem: GankData, newItem: GankData): Boolean {
return oldItem.url.equals(newItem.url)
}
})
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
pagingItemDataViewModel!!.getmLiveData().observe(this, object : Observer> {
override fun onChanged(t: PagedList?) {
adapter!!.submitList(t)
}
})
}
override fun onViewClick(v: View) {
super.onViewClick(v)
}
}
Activity界面中我们只需要关注RecycleView的Adapter的生成。
在上一篇的初识中RecycleView的Adapter需要继承自Paging的PagedListAdapter
public class MyAdapter extends PagedListAdapter {
private Context mContext;
protected MyAdapter(@NonNull DiffUtil.ItemCallback diffCallback) {
super(diffCallback);
}
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mContext = parent.getContext();
return new BaseViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_main, parent, false));
}
@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
TextView tvName = holder.getView(R.id.tv_name);
ImageView imageView = holder.getView(R.id.iv);
GankData data = getItem(position);
tvName.setText(position+"");
GlideUtils.loadImage(mContext,imageView,data.getUrl());
}
}
继承PagedListAdapter,添加构造方法。
可以看到在构造方法中添加以往没有见到的DiffUtil.ItemCallback
protected MyAdapter(@NonNull DiffUtil.ItemCallback diffCallback) {
super(diffCallback);
}
该callback用来判断接收的数据是否为同一个数据
BaseViewHolder相关
public class BaseViewHolder extends RecyclerView.ViewHolder {
private final SparseArray viewSparseArray;
public BaseViewHolder(@NonNull View itemView) {
super(itemView);
viewSparseArray = new SparseArray<>();
}
public T getView(@IdRes int id) {
View view = viewSparseArray.get(id);
if (null == view) {
view = itemView.findViewById(id);
viewSparseArray.put(id, view);
}
return (T) view;
}
}
在Activity中实现DiffUti.ItemCall
adapter = MyAdapter(object : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: GankData, newItem: GankData): Boolean {
return oldItem._id.equals(newItem._id)
}
override fun areContentsTheSame(oldItem: GankData, newItem: GankData): Boolean {
return oldItem.url.equals(newItem.url)
}
})
在areItemsTheSame、areContentsTheSame中编写比较方式。
说了这么多还没有说到数据获取成功时候如何通知RecycleView的Adapter进行数据的更新。
还记得ViewModel中的LiveData对象吗???一个实现了观察者模式的对象。
pagingItemDataViewModel!!.getmLiveData().observe(this, object : Observer> {
override fun onChanged(t: PagedList?) {
// 数据更新,通知adapter更新数据
adapter!!.submitList(t)
}
})
一个简单的observe将数据传递给注册了监听的对象。
这与我们以往使用的不一样, adapter!!.submitList(t) 调用的submit方法就是PagedListAdapter中的方法。它来对数据进行更新显示。
结合自己的业务逻辑按照上述的配置即可完成Paing分页库的使用。
有问题,联系我。