likes
comments
collection
share

SQLDelight for Android - 从SQL语句中生成Kotlin代码 - 2

作者站长头像
站长
· 阅读数 92

扩展

Android分页库

AndroidX Paging2

要在Android分页库中使用SQLDelight, 需要添加分页库的扩展构件.

dependencies {
  implementation "com.squareup.sqldelight:android-paging-extensions:1.5.3"
}

要创建一个DataSource, 写个检索语句来获取行数和接收offset和limit的检索.

countPlayers:
SELECT count(*) FROM hockeyPlayer;

players:
SELECT *
FROM hockeyPlayer
LIMIT :limit OFFSET :offset;
val dataSource = QueryDataSourceFactory(
  queryProvider = playerQueries::players,
  countQuery = playerQueries.countPlayers(),
  transacter = playerQueries,
).create()

AndroidX Paging3

SQLDelight为AndroidX Paging3维护了扩展, 当前处理beta阶段. 引入SQLDelight Paging3扩展:

dependencies {
  implementation "com.squareup.sqldelight:android-paging3-extensions:1.5.3"
}

SQLDelight为分页数据提供了2个方法 -- 偏移分页和键集分页.

偏移分页

偏移分页通过使用OFFSETLIMIT子句达到分页效果. 创建执行偏移分页的PagingSource同分页检索一样, 要求count检索.

countPlayers:
SELECT count(*) FROM hockeyPlayer;

players:
SELECT *
FROM hockeyPlayer
LIMIT :limit OFFSET :offset;
import com.squareup.sqldelight.android.paging3.QueryPagingSource

val pagingSource: PagingSource = QueryPagingSource(
  countQuery = playerQueries.countPlayers(),
  transacter = playerQueries,
  dispatcher = Dispatchers.IO,
  queryProvider = playerQueries::players,
)

默认情况下, 如果没有指定分发器的话, 检索在Dispatchers.IO上面执行. 期待使用RxJava的Scheduler执行检索的话, 应该使用Scheduler.asCoroutineDispatcher扩展函数.

键集分页

偏移分布简单且易于维护. 不幸的是, 它在大型数据集上表现不佳. SQL语句中的OFFSET子句真的直接丢掉SQL检索中已经执行的行. 由此, 随着OFFSET数值增长, 执行检索消耗的时候也增长. 要克服这个缺陷, SQLDelight提供了"键集分页"的实现PagingSource. 与检索完整的数据集和低效地丢弃首个OFFSET元素相反的是, 键集分页通过使用唯一列来限制检索的边界. 这以更高的开发人员维护为代价, 达到了更好的性能. 

PagingSource所接收的queryProvider回调有2个参数 -- beginInclusive是非空唯一Key, 而endExclusive则是可空唯一Key?. 分页检索的核心示例如下所示. 

keyedQuery:
SELECT * FROM hockeyPlayer
WHERE id >= :beginInclusive AND (id < :endExclusive OR :endExclusive IS NULL)
ORDER BY id ASC;

键集分页中的检索必须如上拥有唯一的排序. 

beginInclusiveendExclusive均是预计算的键, 这些键用作页边界. 预计算页边界的时候创建页大小. pageBoundariesProvider回调接收anchor: Key?limit: Long?2个参数. 预计算页边界的示例代码展示如下. 

pageBoundaries:
SELECT id 
FROM (
  SELECT
    id,
    CASE
      WHEN ((row_number() OVER(ORDER BY id ASC) - 0) % :limit) = 0 THEN 1
      WHEN id = :anchor THEN 1
      ELSE 0
    END page_boundary;
  FROM hockeyPlayer
  ORDER BY id ASC
)
WHERE page_boundary = 1;

SQL检索的预计算页边界很可能需要SQLite窗口函数. 窗口函数自SQLite 3.25.0引入, 并由此默认直到Android 30才可用. 要使用键集分页, SQLDelight推荐要么设置minApi 30要么捆绑自己的SQLite版本. Requery提供了SQLite的最新分发作为独立库. 

AndroidX分页库通过PagingConfig.initialLoadSize, 允许首页加载与后续加载的页大小不同. 该函数应该避免使用, 因为pageBoundariesProvider回调只在首页加载时触发一次. PagingConifg.initialLoadSizePagingConfig.pageSize匹配失败将导致意外的页边界产生. 

PagingSource并不支持跳跃. 

要创建PagingSource, 需要使用QueryPagingSource工厂方法. 

import com.squareup.sqldelight.android.paging3.QueryPagingSource

val keyedSource = QueryPagingSource(
  transacter = playerQueries,
  dispatcher = Dispatchers.IO,
  pageBoundariesProvider = playerQueries::pageBoundaries,
  queryProvider = playerQueries::keyedQuery,
)

默认情况下, 如果没有指定分发器的话, 检索在Dispatchers.IO上面执行. 期待使用RxJava的Scheduler执行检索的话, 应该使用Scheduler.asCoroutineDispatcher扩展函数..

转载自:https://juejin.cn/post/7145701856533512199
评论
请登录