(Java实现)使用官方Paging3分页库实现RecyclerView加载更多(loadmore)的功能

Paging是google官方推出的一个分页加载库,配合RecyclerView可以很方便实现RecyelerView的Footer和Header,
Paging3相对以前的版本,实现loadmore的功能更为方便,但因为找了一圈,连Google,stackoverflow,github这些地方也找了一遍,都没有找到关于Paging3的关于java实现代码
,因此自己就根据一些案例,参考了Google迁移到Paging3的说明,实现了最基本的分页加载的功能.Footer和Header的实现有时间可能会写一下.
因为网上也有了一些关于Paging3的教程以及说明.所以这里就不再啰嗦,具体就自己查阅相关资料.

2020.12.21更新:已上传项目至github
项目地址:https://github.com/1831553190/paging3

正文:

使用Paging3,我们可以很方便的做出加载更多的功能,只要滑动到特定的位置就可以自动加载下一页的内容.
Paging3的功能实现,可以使用使用Rxjava或者LiveData,本教程使用的是LiveData来实现;

现在的Paging3已经更新到了alpha07版,因此我们引入Paging库

    implementation "androidx.paging:paging-runtime:3.0.0-alpha07"
    implementation "androidx.paging:paging-guava:3.0.0-alpha07"      //LiveData

以及

    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'  //这里用到了ViewModelKt,所以需要引入,具体是什么玩意请自行搜索,这里不说明

PagingSource:(负责每一分页的数据加载)

Data就是一个普通的实体类

class Data{
      String title;
      String coverImage;

      public String getCoverImage(){
            return coverImage;
      }
      public void setCoverImage(){
            this.coverImage=coverImage;
      }

      public String getTitle(){
            return title;
      }
      public void setTitle(){
            this.title=title;
      }

}


public class LiveDataSource extends ListenableFuturePagingSource<Integer, Data> {
	//需要用到线程池
	private ListeningExecutorService executorService=MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
        String query;
        public LiveDataSource(String query){
            this.query=query;//查询内容所需参数
        }

	@NotNull
	@Override
	public ListenableFuture<LoadResult<Integer, Data>> loadFuture(@NotNull LoadParams<Integer> params) {
		Integer nextPageNumber = params.getKey();
		if (nextPageNumber == null) {
			nextPageNumber = 0;//从第0页开始加载
		}
		Integer finalNextPageNumber = nextPageNumber;
		ListenableFuture<LoadResult<Integer, Data>> pageFuture =Futures
				.transform(executorService.submit(new Callable<List<Data>>() {
			@Override
			public List<Data> call() throws Exception {
				//这里处理耗时操作,比如网络请求数据,数据库数据加载
				NetInterface netInterface = NetWorkUtils.getRetrofit().create(NetInterface.class);
				Response<Msg<PageInfo>> infos = netInterface.getPageInfo(finalNextPageNumber,query).execute();
                                //这里用Roterfit请求网络数据,使用页数和构造函数传过来的参数作为请求参数来请求数据
				return infos.body().getData().getList();//得到数据后返回
			}
		}), new Function<List<Data>, LoadResult.Page<Integer, Data>>() {
			@NotNull
			@Override
			public LoadResult.Page<Integer, Data> apply(@Nullable List<Data> input) {
//				这里传入的三个参数中,刚才请求的数据,第二个参数为请求的上一页的页数,当为null时不再加载上一页,第三个参数则是下一页,后两个参数不介绍,自行了解
				return new LoadResult.Page<>(input,finalNextPageNumber==0?null:finalNextPageNumber-1,input.isEmpty()?null:finalNextPageNumber+1);
			}
		}, executorService);

		ListenableFuture<LoadResult<Integer,Data>> partialLoadResultFuture = Futures.catching(
				pageFuture, Exception.class,
				LoadResult.Error::new, executorService);

		return Futures.catching(partialLoadResultFuture,
				Exception.class, LoadResult.Error::new, executorService);
	}
}


ViewModel:(数据更新观察)

public class LoadMoreViewModel extends ViewModel {
	MutableLiveData<PagingData<Data>> dataMutableLiveData=new MutableLiveData<>();
	PagingConfig pagingConfig=new PagingConfig(10,10,false,10);//初始化配置,可以定义最大加载的数据量

	public LiveData<PagingData<Data>> getPaging(){
		CoroutineScope viewmodelScope= ViewModelKt.getViewModelScope(this);
		Pager<Integer, Data> pager = new Pager<Integer, Data>(pagingConfig, ()->new LiveDataSource("queryId"));构造函数根据自己的需要来调整
		return PagingLiveData.cachedIn(PagingLiveData.getLiveData(pager),viewmodelScope);
	}
}

UI则观察数据的更新,并加载数据

UI:(Fragment或者Activity),可以在onCreate()或者onCreateView()里面写

		listAdapter =new ListAdapter(new DiffUtil.ItemCallback<Data>() {
			@Override
			public boolean areItemsTheSame(@NonNull Data oldItem, @NonNull Data newItem) {
				return oldItem.getId()==newItem.getId();
			}

			@Override
			public boolean areContentsTheSame(@NonNull Data oldItem, @NonNull Data newItem) {
				return oldItem.getTitle().equals(newItem.getTitle());
			}
		});
		recyclerView.setAdapter(listAdapter);
		LoadMoreViewModel loadMoreViewModel=new ViewModelProvider(this).get(LoadMoreViewModel.class);
		loadMoreViewModel.getPaging().observe(getViewLifecycleOwner(),
				dataInfoPagingData -> listAdapter.submitData(getLifecycle(),dataInfoPagingData));//观察数据的更新

Adapter:(基本和原来一样,但是继承的类不一样了)


public class ListAdapter extends PagingDataAdapter<Data, ListAdapter.Holder> {


	public ListAdapter(@NotNull DiffUtil.ItemCallback<Data> diffCallback) {
		super(diffCallback);
	}


	@NonNull
	@Override
	public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
		return new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_info,parent,false));
	}

	@Override
	public void onBindViewHolder(@NonNull Holder holder, int position) {
		holder.title.setText(getItem(position).getTitle());
		Glide.with(holder.itemView.getContext())
				.load(getItem(position).getCoverImage())
				.crossFade()
				.error(R.mipmap.img)
				.into(holder.cover);
		
	}

	class Holder extends RecyclerView.ViewHolder{
		TextView title;
		ImageView cover;
		public Holder(@NonNull View itemView) {
			super(itemView);
			title=itemView.findViewById(R.id.text_title);
			cover=itemView.findViewById(R.id.img_coverPicture);
		}
	}
}

需要写的代码基本就这么多

gif暂时没有,代码中也用到了一部分lambda表达式(为了简化一点代码)

posted @ 2020-10-27 19:19  犯二的二  阅读(3419)  评论(0编辑  收藏  举报