Compose + Paging3+Room完成列表分页展示功能

1,189 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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)
            }
        }
    }
}