95 lines
2.5 KiB
Kotlin
95 lines
2.5 KiB
Kotlin
package com.looker.droidify.database
|
|
|
|
import android.content.Context
|
|
import android.database.Cursor
|
|
import android.os.CancellationSignal
|
|
import android.os.OperationCanceledException
|
|
import androidx.loader.content.AsyncTaskLoader
|
|
|
|
class QueryLoader(context: Context, private val query: (CancellationSignal) -> Cursor?) :
|
|
AsyncTaskLoader<Cursor>(context) {
|
|
private val observer = ForceLoadContentObserver()
|
|
private var cancellationSignal: CancellationSignal? = null
|
|
private var cursor: Cursor? = null
|
|
|
|
override fun loadInBackground(): Cursor? {
|
|
val cancellationSignal = synchronized(this) {
|
|
if (isLoadInBackgroundCanceled) {
|
|
throw OperationCanceledException()
|
|
}
|
|
val cancellationSignal = CancellationSignal()
|
|
this.cancellationSignal = cancellationSignal
|
|
cancellationSignal
|
|
}
|
|
try {
|
|
val cursor = query(cancellationSignal)
|
|
if (cursor != null) {
|
|
try {
|
|
cursor.count // Ensure the cursor window is filled
|
|
cursor.registerContentObserver(observer)
|
|
} catch (e: Exception) {
|
|
cursor.close()
|
|
throw e
|
|
}
|
|
}
|
|
return cursor
|
|
} finally {
|
|
synchronized(this) {
|
|
this.cancellationSignal = null
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun cancelLoadInBackground() {
|
|
super.cancelLoadInBackground()
|
|
|
|
synchronized(this) {
|
|
cancellationSignal?.cancel()
|
|
}
|
|
}
|
|
|
|
override fun deliverResult(data: Cursor?) {
|
|
if (isReset) {
|
|
data?.close()
|
|
} else {
|
|
val oldCursor = cursor
|
|
cursor = data
|
|
if (isStarted) {
|
|
super.deliverResult(data)
|
|
}
|
|
if (oldCursor != data) {
|
|
oldCursor.closeIfNeeded()
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onStartLoading() {
|
|
cursor?.let(this::deliverResult)
|
|
if (takeContentChanged() || cursor == null) {
|
|
forceLoad()
|
|
}
|
|
}
|
|
|
|
override fun onStopLoading() {
|
|
cancelLoad()
|
|
}
|
|
|
|
override fun onCanceled(data: Cursor?) {
|
|
data.closeIfNeeded()
|
|
}
|
|
|
|
override fun onReset() {
|
|
super.onReset()
|
|
|
|
stopLoading()
|
|
cursor.closeIfNeeded()
|
|
cursor = null
|
|
}
|
|
|
|
private fun Cursor?.closeIfNeeded() {
|
|
if (this != null && !isClosed) {
|
|
close()
|
|
}
|
|
}
|
|
}
|