SQLDelight in Android: Getting Started

Aug 3 2021 · Kotlin 1.4, Android 11, Android Studio 4.1

Part 2: Advanced SQLDelight Integrations

14. Integrate with Android Paging

Episode complete

About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 13. Integrate with Kotlin Coroutines

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 14. Integrate with Android Paging

For more insight into what the Android Paging library can do for apps beyond what’s covered here, check out the official docs on the subject.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

The Android Paging library helps developers deal with segmented access to long lists of data. Assuming that the power users of our bug collector app could aggregate hundreds and thousands of collections over time, the performance of the app may start to degrade over time when all data is pulled from the database at the same time.

dependencies {
    implementation "com.squareup.sqldelight:android-paging-extensions:$sqldelightVersion"

    // Android Paging
    implementation "androidx.paging:paging-runtime-ktx:2.1.2"
}
+count:
+SELECT count(*) FROM collection;

all:
-SELECT * FROM collection;
+SELECT * FROM collection
+LIMIT :limit OFFSET :offset;
-fun listCollections(): Query<Collection> {
+fun listCollections(): DataSource.Factory<Int, Collection> {
    return database.collectionQueries.all()
}
fun listCollections(): DataSource.Factory<Int, Collection> {
-    return database.collectionQueries.all()
+    return QueryDataSourceFactory(
+
+    )    
}
fun listCollections(): DataSource.Factory<Int, Collection> {
    return QueryDataSourceFactory(
+        queryProvider = database.collectionQueries::all,
+        countQuery = database.collectionQueries.count(),
+        transacter = database.collectionQueries
    )
}
-private val collectionQueryListener = object : Query.Listener {
-    override fun queryResultsChanged() {
-        refreshState()
-    }
-}
-private val collectionQuery = repository.listCollections()
+private val collectionQuery = repository.listCollections().toLiveData(pageSize = 3)
+private val observer = Observer<PagedList<Collection>> { collections ->
+    _state.value = State.Result(
+        collections = collections
+    )
+}

init {
-    refreshState()
-
-    collectionQuery.addListener(collectionQueryListener)
+    collectionQuery.observeForever(observer)
}
override fun onCleared() {
-    collectionQuery.removeListener(collectionQueryListener)
+    collectionQuery.removeObserver(observer)
}
-private fun refreshState() {
-    _state.value = State.Result(
-        collections = collectionQuery.executeAsList()
-    )
-}

sealed class State {
    object Loading : State()
-    data class Result(val collections: List<Collection>): State()
+    data class Result(val collections: PagedList<Collection>): State()
}
-class CollectionListAdapter : ListAdapter<Collection, CollectionHolder>(diffCallback) {
+class CollectionListAdapter : PagedListAdapter<Collection, CollectionHolder>(diffCallback) {

  override fun onBindViewHolder(holder: CollectionHolder, position: Int) {
    // Ensure a formatter is available to format the collection's timestamp.
    // Create the object when the first ViewHolder is being bound
    val formatter = this.formatter ?: holder.itemView.resources
      .getDateTimeFormatter(R.string.timestamp_format)
      .also { this.formatter = it }

    // Style
    val item = getItem(position)
-    holder.idTextView.text = "#${item.collectionId}"
-    holder.nameTextView.text = item.name
-    holder.creationTextView.text = item.creationTime.format(formatter)
-
-    // Listeners
-    holder.layout.setOnClickListener { _clickEvents.offer(item.collectionId) }
+
+    if (item != null) {
+        holder.idTextView.text = "#${item.collectionId}"
+        holder.nameTextView.text = item.name
+        holder.creationTextView.text = item.creationTime.format(formatter)
+        holder.layout.setOnClickListener { _clickEvents.offer(item.collectionId) }
+    } else {
+        holder.idTextView.text = "..."
+        holder.nameTextView.text = null
+        holder.creationTextView.text = null
+        holder.layout.setOnClickListener(null)
+    }
}