AndroidX Paging
SQLDelightをAndroidのPaging 3ライブラリと連携して使用するには、ページング拡張アーティファクトへの依存関係を追加します。 AndroidX Pagingのマルチプラットフォーム対応は、Multiplatform Pagingを介して提供されます。
kotlin {
sourceSets.commonMain.dependencies {
implementation("app.cash.sqldelight:androidx-paging3-extensions:2.1.0")
}
}kotlin {
sourceSets.commonMain.dependencies {
implementation "app.cash.sqldelight:androidx-paging3-extensions:2.1.0"
}
}SQLDelightは、オフセットベースのページングとキーセットページングという2つのデータページング方法を提供します。
オフセットベースのページング
オフセットページングは、OFFSET句とLIMIT句を使用してページングされた結果を実現します。オフセットベースのページングを実行するPagingSourceを作成するには、カウントクエリとページングされるクエリの両方が必要です。
countPlayers:
SELECT count(*) FROM hockeyPlayer;
players:
SELECT *
FROM hockeyPlayer
LIMIT :limit OFFSET :offset;import app.cash.sqldelight.android.paging3.QueryPagingSource
val pagingSource: PagingSource = QueryPagingSource(
countQuery = playerQueries.countPlayers(),
transacter = playerQueries,
context = Dispatchers.IO,
queryProvider = playerQueries::players,
)デフォルトでは、コンテキストが指定されていない場合、クエリはDispatchers.IOで実行されます。RxJavaのSchedulerを使用してクエリを実行することを想定しているコンシューマは、Scheduler.asCoroutineDispatcher拡張関数を使用すべきです。
キーセットページング
オフセットページングはシンプルで保守が容易です。残念ながら、大規模なデータセットではパフォーマンスが低下します。SQLステートメントのOFFSET句は、実際にはSQLクエリですでに実行された行を単に破棄するだけです。したがって、OFFSETの数値が増加するにつれて、クエリの実行にかかる時間も増加します。これを克服するために、SQLDelightはPagingSourceの「キーセットページング」実装を提供します。データセット全体をクエリし、最初のOFFSET要素を非効率的に破棄するのではなく、キーセットページングは一意の列を使用してクエリの境界を制限します。これは、開発者のメンテナンスコストが高くなるという犠牲を払って、より優れたパフォーマンスを発揮します。
このページングソースが受け入れるqueryProviderコールバックは、beginInclusiveというnull非許容の一意なKeyと、endExclusiveというnull許容の一意なKey?という2つのパラメータを持っています。コアページングクエリの例を以下に示します。
keyedQuery:
SELECT * FROM hockeyPlayer
WHERE id >= :beginInclusive AND (id < :endExclusive OR :endExclusive IS NULL)
ORDER BY id ASC;キーセットページングで使用されるクエリは、上記のように一意の順序付けを持つ必要があります。
beginInclusiveとendExclusiveは、ページ境界として機能する_事前に計算された_キーです。ページ境界を事前に計算するときにページサイズが設定されます。pageBoundariesProviderコールバックは、anchor: Key?パラメータとlimit: Int?パラメータを受け取ります。ページ境界を事前に計算するクエリの例を以下に示します。
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 Window Functionsが必要となる可能性が高いです。ウィンドウ関数はSQLiteバージョン3.25.0で導入されたため、Android API 30まではデフォルトでは利用できません。キーセットページングを使用するには、SQLDelightはminApi 30を設定するか、独自のSQLiteバージョンをバンドルすることを推奨します。Requery組織は、スタンドアロンライブラリとしてSQLiteの最新ディストリビューションを提供しています。
AndroidX pagingライブラリでは、PagingConfig.initialLoadSizeを使用して、最初のページフェッチのサイズを以降のページフェッチと異なるように設定できます。pageBoundariesProviderコールバックは最初のページフェッチ時に一度だけ呼び出されるため、この機能は避けるべきです。PagingConfig.initialLoadSizeとPagingConfig.pageSizeが一致しない場合、予期せぬページ境界の生成につながります。
このページングソースはジャンプを_サポートしていません_。
このページングソースを作成するには、QueryPagingSourceファクトリ関数を使用します。
import app.cash.sqldelight.android.paging3.QueryPagingSource
val keyedSource = QueryPagingSource(
transacter = playerQueries,
context = Dispatchers.IO,
pageBoundariesProvider = playerQueries::pageBoundaries,
queryProvider = playerQueries::keyedQuery,
)デフォルトでは、コンテキストが指定されていない場合、クエリはDispatchers.IOで実行されます。RxJavaのSchedulerを使用してクエリを実行することを想定しているコンシューマは、Scheduler.asCoroutineDispatcher拡張関数を使用すべきです。
