1. paging3相关依赖的引入:
ext {
room_version = "2.4.2"
paging_version = "3.1.1"
lifecycle_version = "2.4.1"
}
dependencies {
//paging3 adapter数据需要返回主线程,绑定生命周期进行加载
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
//paging3的java和kotlin依赖
implementation "androidx.paging:paging-common:$paging_version"
implementation "androidx.paging:paging-runtime:$paging_version"
implementation "androidx.paging:paging-common-ktx:$paging_version"
implementation "androidx.paging:paging-runtime-ktx:$paging_version"
//如果使用了Jetpack room作为本地化数据存储就需要引入这个依赖进行配合
implementation "androidx.room:room-paging:$room_version"
}
2. adapter的创建
需要继承PagingDataAdapter<T : Any, VH : RecyclerView.ViewHolder>类,并重写DiffUtil.ItemCallback接口进行初始化。
class AlbumAdapter(private val listener:(String) -> Unit): PagingDataAdapter<SystemPhotoBean,BaseViewHolder<ItemAlbumBinding>>(diffCallback) {
companion object {
val diffCallback = object : DiffUtil.ItemCallback<SystemPhotoBean>() {
override fun areItemsTheSame(oldItem: SystemPhotoBean, newItem: SystemPhotoBean): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: SystemPhotoBean, newItem: SystemPhotoBean): Boolean {
return oldItem == newItem
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ItemAlbumBinding> = BaseViewHolder(ItemAlbumBinding.inflate(LayoutInflater.from(parent.context),parent,false))
//其他的实现...
}
3. 搭配room进行数据加载
room接口的实现(很简单只需要在对应的接口返回PagingSource就行):
@Dao
interface PhotoDAO {
@Query("select * from sy_photo_info")
fun getPhotoDataSource(): PagingSource<Int,SystemPhotoBean>
}
之后需要对Pager进行初始化,在内部需要实现PagingConfig参数配置以及将刚刚room接口实现的PagingSource方法进行引用即可。Pager可生成flow也可生成livedata。
//生成flow
fun getPhotoDataSource(): Flow<PagingData<SystemPhotoBean>> = Pager(PagingConfig(pageSize = 20, enablePlaceholders = true, initialLoadSize = 60)) {
cache.getPhotoDataSource()
}.flow
//生成livedata
fun getPhotoDataSource(): LiveData<PagingData<SystemPhotoBean>> = Pager(PagingConfig(pageSize = 20, enablePlaceholders = true, initialLoadSize = 60)) {
photoDAO.getPhotoDataSource()
}.liveData
PagingConfig内部有pageSize、prefetchDistance、enablePlaceholders、initialLoadSize、maxSize五个参数;
pageSize:每页显示的数据的大小;
prefetchDistance:预刷新的距离,距离最后一个 item 多远时加载数据;
enablePlaceholders:是否显示占位符;
initialLoadSize:初始化加载数量;
maxSize:最大数据;
4. 将Pager绑定在adapter上
adapter绑定在list不用多讲,adapter绑定Pager有两种方式,submitData提供带Lifecycle方法和suspend fun协程方法;
//方法一:
lifecycle.coroutineScope.launch {
viewModel.photoList.collectLatest {
adapter.submitData(it)
}
}
//方法二:
viewModel.photoList.collectLatest {
adapter.submitData(this.lifecycle, it)
}
5. 网络数据的加载:
需要自己实现PagingSource类的处理逻辑,其他实现跟以上教程没有太多区别。
Pager(PagingConfig(pageSize)) {
object : PagingSource<Int, LiveCoursesBean>() {
var pageNum: Int = 1
override fun getRefreshKey(state: PagingState<Int, LiveCoursesBean>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LiveCoursesBean> {
return try {
//你的api网络请求数据
val data = api.getListData(pageNum, pageSize).data
//根据你后台返回的数据自行判断
when {
data != null && data.list.size > 0 && pageNum <= data.pageNum -> {
pageNum++
LoadResult.Page(data = data.list, prevKey = null, nextKey = pageNum)
}
else -> LoadResult.Page(data = arrayListOf(), prevKey = null, nextKey = null)
}
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
}.flow
LoadResult.Page在有数据、没有报错的情况下将你的数据进行返回,list就会自行呈现数据。
LoadResult.Error在报错情况下进行调用,在adapter中可以实现状态接口进行监听。
adapter监听:
//用于下拉刷新组件的配合使用
adapter.addLoadStateListener {
layout.refresh.isRefreshing = it.refresh is LoadState.Loading
}
it.refresh为adapter的状态,通过对refresh进行判断来执行不同的操作和相关UI的显示。
6. 数据的刷新与出错重载
adapter.refresh()//重新从第一页加载
adapter.retry()//从加载失败的地方再次加载