(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 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);

	}

	 

	 

	 

	 

	}

	 

	 

	@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) {

		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);

	}

	 

	 

	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));//观察数据的更新</code></pre>

	 

	 

	 

	 

	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);

		}

	}

	 

	 

	 

	 

	}

	 

	 

			@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));//观察数据的更新</code></pre>

	 

	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);

		}

	}

	 

	 

	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);

		}

	}

	}

posted @ 2023-03-23 09:35  cps666  阅读(40)  评论(0编辑  收藏  举报