持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
Compose + Paging3+Room完成列表分页展示功能
结合之前我们分享的Compose和Room的文章,我们今天做了一个将两个结合的Demo,下面我们就继续我们今天的分享
我们使用Room存放本地数据,使用Paging3的Compose版本来将数据进行分页处理,将数据展示在Compose编写的界面中。
Room部分我们先定义表结构OrderEntity
@Entity(tableName = "table_book", indices = [Index(value = ["bookCode"], unique = true)])
data class BookEntity(
@PrimaryKey
var bookCode:String,
var bookType:Int,
var bookPrice:String,
var createTime: Date
)
编写Dao,进行订单查询的并且还要进行分页
@Dao
interface BookDao {
@Query("SELECT * FROM table_book WHERE (case :bookType when 0 then 1 else bookType =:bookType END) ORDER BY createTime DESC LIMIT :pageSize OFFSET :pageOffset")
suspend fun queryAllOrder(bookType:Int,pageSize:Int,pageOffset: Int):List<BookEntity>
}
上面查询SQL语句中WHERE子句由于我们编写的Demo使用了Tab来进行订单状态的过滤,所以看个人情况可以需不需要。ORDER BY 子句时要让查询按订单最新的展示,LIMIT 是我们的分页大小, OFFSET 子句是页偏移量
DataBase的创建和我们之前分享的一样
//实体表类
@Database(
entities = [ BookEntity::class],
version = 1, exportSchema = false
)
//复杂数据类型的转换类
@TypeConverters(
value = [DateTypeConverters::class]
)
abstract class AppDatabase : RoomDatabase() {
//Dao的访问实例
abstract fun bookDao(): BookDao
companion object {
@Volatile
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "db_name")
.addCallback(
object : AppDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
}
}
)
.build()
}
}
}
然后我们需要完成Paging 分页部分的代码
PagingSource.kt
class BookPagerSource @Inject constructor(
private val db: DemoDatabase = DemoDatabase.getInstance(App.getContext()),
val bookType: Int,
) : PagingSource<Int, BookEntity>() {
override fun getRefreshKey(state: PagingState<Int, BookEntity>): Int? {
return state.anchorPosition?.let {
val anchorPage = state.closestPageToPosition(it)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, BookEntity> {
//下一页的页码索引
val nextPageIndex = params.key ?: 0
val pageData =
db.orderDao().queryAllOrder(
bookType = bookType,
params.loadSize,
nextPageIndex * params.loadSize
)
return try {
LoadResult.Page(
data = pageData,
prevKey = if (nextPageIndex == 0) null else nextPageIndex.minus(1),
nextKey = if (pageData.isEmpty()) null else nextPageIndex.plus(1)
)
} catch (e: Exception) {
return LoadResult.Error(e)
}
}
}
Repository层
//ORDER_PAGER_SIZE为页大小 我们定义的是20 orderState是需要查询的订单状态类型
fun getAllBookList(bookType:Int) = Pager(PagingConfig(pageSize = ORDER_PAGER_SIZE)) {
BookPagerSource(bookType = bookType)
}.flow
ViewModel
//由于我们界面切换书籍类型需要触发可组合项重组,所以需要将数据使用MutableState包装
var bookPager: MutableState<Flow<PagingData<BookEntity>>?> = mutableStateOf(null)
//该方法时调用repository的获取数据源方法进行数据获取
fun getOrderData(){
//bookType 为状态选中的书籍类型
bookPager.value =repository.getAllBookrList(bookType.value.type).flowOn(Dispatchers.IO).cachedIn(viewModelScope)
}
接下来就咱们使用Compose界面编写
@Composable
fun BookList(
modifier: Modifier
) {
val listState = rememberLazyListState()
val viewModel: OrderViewModel = viewModel()
val lazyBookItem = viewModel.bookPager.value!!.collectAsLazyPagingItems()
LazyColumn(modifier = modifier, state = listState) {
//表头
stickyHeader {
//表头布局
BookListHeader(
modifier = Modifier
.height(41.hdp)
.background(greenF2FFFD)
)
}
//数据展示
itemsIndexed(lazyBookItem) { index, item ->
item?.let {
//Item布局
BookListItem(index = index, order = item, modifier = Modifier)
}
}
}
}