概述
Compose中Paging3
的使用和Recycleview中Paging3的使用基本一致,不同的是Compose
中我们的ui使用LazyColumn
来承载数据。
我们需要做的事情如下:
- 配置
PagingSource
- 配置数据类
SimpleUseBean
- 配置
ViewModel
- 在LazyColumn中渲染数据
简单加载数据
依赖
var paging_version = "3.0.1" implementation("androidx.paging:paging-runtime:$paging_version") testImplementation("androidx.paging:paging-common:$paging_version") implementation("androidx.paging:paging-compose:1.0.0-alpha12") 复制代码
数据类
data class SimpleUseBean(val data: String="") 复制代码
ViewModel
class SimpleUseViewModel : ViewModel() { val projects = Pager(PagingConfig(pageSize = 20)){ SimpleUseSource() }.flow.cachedIn(viewModelScope) } 复制代码
配置PagingSource
class SimpleUseSource : PagingSource<Int, SimpleUseBean>() { override fun getRefreshKey(state: PagingState<Int, SimpleUseBean>): Int? =null override suspend fun load(params: LoadParams<Int>): LoadResult<Int, SimpleUseBean> { return try { val nextPage = params.key ?: 1 val datas = mutableListOf( SimpleUseBean("哈哈${params.key}"), SimpleUseBean("哈哈${params.key}"), SimpleUseBean("哈哈${params.key}"), SimpleUseBean("哈哈${params.key}"), SimpleUseBean("哈哈${params.key}") ) LoadResult.Page( data = datas, prevKey = if (nextPage == 1) null else nextPage - 1, nextKey = if (nextPage < 100) nextPage + 1 else null ) } catch (e: Exception) { LoadResult.Error(e) } } } 复制代码
渲染数据
@Composable fun simpleUse() { val model = viewModel<SimpleUseViewModel>() val datas = model.projects.collectAsLazyPagingItems() LazyColumn(content = { itemsIndexed(datas) { _, data -> Box( Modifier .padding(horizontal = 14.dp,vertical = 4.dp) .fillMaxWidth() .height(60.dp) .border(1.dp, Color.Red, RoundedCornerShape(5.dp)) .padding(start = 10.dp) , contentAlignment = Alignment.CenterStart ) { Text(text = data?.data ?: "") } } }) } 复制代码
实现效果
使用Compose、SwipeRefresh、LazyColumn实现刷新和加载数据
依赖
SwipeRefresh依赖
implementation ("com.google.accompanist:accompanist-swiperefresh:0.18.0") 复制代码
PagingSource
class RefreshLoadUseSource : PagingSource<Int, RefreshData>() { override fun getRefreshKey(state: PagingState<Int, RefreshData>): Int? = null override suspend fun load(params: LoadParams<Int>): LoadResult<Int, RefreshData> { return try { val nextPage = params.key ?: 1 if (nextPage < 13) { delay(1500) val datas = mutableListOf( RefreshData("哈哈${params.key}"), RefreshData("哈哈${params.key}"), RefreshData("哈哈${params.key}"), RefreshData("哈哈${params.key}"), RefreshData("哈哈${params.key}") ) LoadResult.Page( data = datas, prevKey = if (nextPage == 1) null else nextPage - 1, nextKey = if (nextPage < 100) nextPage + 1 else null ) } else {//超过13条就加载错误 LoadResult.Error(NullPointerException("空指针")) } } catch (e: Exception) { LoadResult.Error(e) } } } 复制代码
ViewModel和数据实体
data class RefreshData(val data: String) 复制代码
class RefreshLoadUseViewModel : ViewModel() { val datas = Pager(PagingConfig(pageSize = 20)) { RefreshLoadUseSource() }.flow.cachedIn(viewModelScope) } 复制代码
ui代码
@Composable fun refreshLoadUse() { val refreshState = rememberSwipeRefreshState(isRefreshing = false) val model = viewModel<RefreshLoadUseViewModel>() val collectAsLazyPagingItems = model.datas.collectAsLazyPagingItems() SwipeRefresh(state = refreshState, onRefresh = { collectAsLazyPagingItems.refresh() }) { LazyColumn( modifier = Modifier .fillMaxWidth() .fillMaxHeight(), content = { itemsIndexed(collectAsLazyPagingItems) { _, refreshData ->//每个item的展示 Box( modifier = Modifier .padding(horizontal = 14.dp, vertical = 4.dp) .fillMaxWidth() .height(50.dp) .background(Color.Green,shape= RoundedCornerShape(8.dp)) .border( width = 1.dp, color = Color.Red, shape = RoundedCornerShape(8.dp) ) .padding(start = 10.dp), contentAlignment = Alignment.CenterStart ) { Text(text = refreshData?.data ?: "") } } when (collectAsLazyPagingItems.loadState.append) { is LoadState.Loading -> {//加载中的尾部item展示 item { Box( modifier = Modifier .fillMaxWidth() .height(50.dp), contentAlignment = Alignment.Center ) { Text(text = "加载中。。。") } } } else -> {//加载完成或者加载错误展示的尾部item item { Box( modifier = Modifier .fillMaxWidth() .height(50.dp), contentAlignment = Alignment.Center ) { Text(text = "--加载完成或加载错误--") } } } } }) } } 复制代码
实现效果
Room+RemoteMediator实现数据的插入和删除(2022-04-17补充)
太累了,这次补充直接上代码和效果了
代码
@Composable fun RoomLoadPage() { val model: RoomLoadPageModel = viewModel() val pagingData = model.projects.collectAsLazyPagingItems() // val listState = rememberLazyListState() val swipeState = rememberSwipeRefreshState(isRefreshing = false) Column { Button(onClick = { model.insert() }) { Text(text = "插入数据") } SwipeRefresh(state = swipeState, onRefresh = { pagingData.refresh() }) { LazyColumn(content = { swipeState.isRefreshing = false itemsIndexed(pagingData) { index, goods -> if (goods != null) { Box(Modifier .fillMaxWidth() .height(80.dp), contentAlignment = Alignment.Center) { Row( Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceAround ) { Text(text = goods.name) Button(onClick = { model.delete(goods) }) { Text(text = "删除") } Button(onClick = { model.modify(goods, index) }) { Text(text = "修改") } } } } } }) } } } class RoomLoadPageModel : ViewModel() { // val db = // Room.databaseBuilder(App.app, GoodsDatabase::class.java, "goods") // .allowMainThreadQueries() // .build() val db = Room.inMemoryDatabaseBuilder(App.app, GoodsDatabase::class.java) .allowMainThreadQueries() .build() private var count = 0 @OptIn(ExperimentalPagingApi::class) val projects = Pager( PagingConfig(pageSize = 20), remoteMediator = RoomRemoteMediator(callback = { loadType, pagingState -> Goods("商品:${++count}").let { db.goodsDao().insertAll(it) } RemoteMediator.MediatorResult.Success(false) }), ) { val start = System.currentTimeMillis() val data = db.goodsDao().getAll1() logEE("加载时间:${System.currentTimeMillis() - start}") data }.flow.cachedIn(viewModelScope) fun insert() { viewModelScope.launch { db.goodsDao().insertAll(listOf(Goods(name = "aaa${++count}"))) } } fun delete(goods: Goods) { db.goodsDao().delete(goods) } override fun onCleared() { super.onCleared() db.clearAllTables() } /** * 更新item数据 */ fun modify(goods: Goods, index: Int) { db.goodsDao().update(goods.apply { name = "---名字被修改" }) } } class RoomLoadPageSource(val callback: suspend (params: LoadParams<Int>) -> LoadResult<Int, Goods>) : PagingSource<Int, Goods>() { override fun getRefreshKey(state: PagingState<Int, Goods>): Int? = null override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Goods> { return callback(params) } } @OptIn(ExperimentalPagingApi::class) class RoomRemoteMediator(val callback: suspend (LoadType, PagingState<Int, Goods>) -> MediatorResult) : RemoteMediator<Int, Goods>() { override suspend fun load(loadType: LoadType, state: PagingState<Int, Goods>): MediatorResult { return callback(loadType, state) } } @Dao interface GoodsDao { @Query("SELECT * FROM goods order by goodsName ASC") fun getAll(): List<Goods> @Query("SELECT * FROM goods") fun getAll1(): PagingSource<Int, Goods> @Insert fun insertAll(vararg users: Goods) @Insert fun insertAll(users: List<Goods>) @Delete fun delete(user: Goods) @Update fun update(goods: Goods) } @Entity data class Goods( @PrimaryKey(autoGenerate = false) @ColumnInfo(name = "goodsName") var name: String, ) { // @PrimaryKey(autoGenerate = true) // var id: Long? = null } @Database(entities = arrayOf(Goods::class), version = 1) abstract class GoodsDatabase : RoomDatabase() { abstract fun goodsDao(): GoodsDao } 复制代码
效果