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表達式(為了簡化一點代碼)