概述
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
}