「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战
添加依赖
implementation "androidx.paging:paging-runtime:3.0.0-beta02"
implementation "androidx.paging:paging-compose:1.0.0-alpha08"
retrofit2的使用方法这里就赘述了,我尽量演示地通俗易懂。
retrofit2的流程是
初始化Retrofit
创建一个全局可用的retrofit对象,通常都是单例模式
编写请求接口
构建repository
推荐一篇文章[Android帅次]的
❤️Android OkHttp+Retrofit+Rxjava+Hilt实现网络请求框架❤️
回到正题
Paging3的使用
paging.pager
Primary entry point into Paging; constructor for a reactive stream of PagingData.
翻译一下就是
分页的主要入口点;分页数据的反应流的构造函数。
这家伙长这样
public class Pager<Key : Any, Value : Any>
// 通过构造函数参数传播到公共 API。
@ExperimentalPagingApi constructor(
config: PagingConfig,
initialKey: Key? = null,
remoteMediator: RemoteMediator<Key, Value>?,
pagingSourceFactory: () -> PagingSource<Key, Value>
)
有四个参数
PagingConfig
先说PagingConfig 有5个配置
| PagingConfig参数 | 默认值 |
|---|---|
| pageSize: Int | 无 |
| prefetchDistance: Int | pageSize |
| enablePlaceholders: Boolean | true |
| initialLoadSize: Int | pageSize * 3 |
| maxSize: Int | 无限 |
PagingConfig: 从分页源加载内容时,用于配置分页器内加载行为的对象
定义从PagingSource一次加载的项目数。
pageSize
应该是屏幕上可见项目数的几倍。 注意:pageSize用于通知PagingSource。加载参数。loadSize,但不强制执行。PagingSource可能完全忽略此值,但仍返回有效页面。
prefetchDistance
prefetchDistance 默认等于 = pageSize 定义如果分页源提供空占位符,则分页数据是否可以显示空占位符。
如果满足以下两个条件,PagingData将为尚未加载的内容显示空占位符:
1.它的PagingSource可以计算所有已卸载的项(以便知道要显示的空值的数量)。 2.enablePlaceholders设置为true
enablePlaceholders
为PagingSource的初始加载定义请求的加载大小,通常大于pageSize,因此在第一次加载数据时,加载的内容范围足够大,可以覆盖小的滚动条。
注意:initialLoadSize用于通知PagingSource。加载参数。loadSize,但不强制执行。PagingSource可能会完全忽略此值,但仍会返回有效的初始页面
initialLoadSize
定义在删除页面之前可以加载到PagingData中的最大项目数。
maxSize
最大值嘛
initialKey
新建一个实体来装PagingConfig的配置
data class AppPagingConfig
PagingSource
我们用Pager的 config和initialKey就可以了
先重写load和getRefreshKey方法
抽出来做进一步的封装
config: AppPagingConfig = AppPagingConfig()
initialKey: K? = null
...
Pager(
config = baseConfig,
initialKey = initialKey
) {
object : PagingSource<K, V>() {
override suspend fun load(params: LoadParams<K>): LoadResult<K, V> {
return loadData.invoke(params)
}
override fun getRefreshKey(state: PagingState<K, V>): K? {
return initialKey
}
}
}.flow.cachedIn(viewModelScope)
loadData: suspend (PagingSource.LoadParams<K>) -> PagingSource.LoadResult<K, V>
在loadData里面做网络请求的逻辑
请求成功时返回LoadResult.Page,失败时返回LoadResult.Error
完整代码
fun <T : Any> ViewModel.simplePager(
config: AppPagingConfig = AppPagingConfig(),
callAction: suspend (page: Int) -> BasicBean<ListWrapper<T>>
): Flow<PagingData<T>> {
return pager(config, 0) {
val page = it.key ?: 0
val response = try {
//请求到的数据
HttpResult.Success(callAction.invoke(page))
} catch (e: Exception) {
HttpResult.Error(e)
}
when (response) {
is HttpResult.Success -> {
val data = response.result.data
val hasNotNext = (data!!.datas.size < it.loadSize) && (data.over)
//LoadResult.Page详细可看上篇文章
//data= 请求到的数据内容
PagingSource.LoadResult.Page(
data = response.result.data!!.datas,
prevKey = if (page - 1 > 0) page - 1 else null,
nextKey = if (hasNotNext) null else page + 1
)
}
is HttpResult.Error -> {
PagingSource.LoadResult.Error(response.exception)
}
}
}
}
fun <K : Any, V : Any> ViewModel.pager(
config: AppPagingConfig = AppPagingConfig(),
initialKey: K? = null,
loadData: suspend (PagingSource.LoadParams<K>) -> PagingSource.LoadResult<K, V>
): Flow<PagingData<V>> {
val baseConfig = PagingConfig(
config.pageSize,
initialLoadSize = config.initialLoadSize,
prefetchDistance = config.prefetchDistance,
maxSize = config.maxSize,
enablePlaceholders = config.enablePlaceholders
)
return Pager(
config = baseConfig,
initialKey = initialKey
) {
object : PagingSource<K, V>() {
override suspend fun load(params: LoadParams<K>): LoadResult<K, V> {
return loadData.invoke(params)
}
override fun getRefreshKey(state: PagingState<K, V>): K? {
return initialKey
}
}
}.flow.cachedIn(viewModelScope)
}
data class AppPagingConfig(
val pageSize: Int = 20,
val initialLoadSize: Int = 20,
val prefetchDistance:Int = 1,
val maxSize:Int = PagingConfig.MAX_SIZE_UNBOUNDED,
val enablePlaceholders:Boolean = false
)
使用方法
在ViewModel里配置paging的数据 用flow将数据转换为Flow的形式,cachedIn(viewModelScope)将数据缓存在viewmodel中
private val pager by lazy {
simplePager {
//it = 加载的页数
//根据页数来请求数据
service.getSquareData(it)
}.cachedIn(viewModelScope)
}
var viewStates by mutableStateOf(ViewState(pagingData = pager))
private set
data class ViewState(
val pagingData: PagingBean
)
typealias PagingBean = Flow<PagingData<实体类>>
渲染UI
val viewStates = remember { viewModel.viewStates }
val squareData = viewStates.pagingData.collectAsLazyPagingItems()
LazyColumn() {
itemsIndexed(squareData) { _, item ->
Text(text = item.data)
}
}
下一篇 配和SwipeRefresh 下拉刷新一起使用