Merge changes from topic "room-runtime-paging-kotlinify" into androidx-main
* changes:
Converting `paging` related files in `room-runtime` from Java to Kotlin.
Initial code check-in for renaming `paging` related files in `room-runtime` from *.java to *.kt.
diff --git a/room/room-runtime/api/restricted_current.ignore b/room/room-runtime/api/restricted_current.ignore
index e6a9bf9..a566a8f 100644
--- a/room/room-runtime/api/restricted_current.ignore
+++ b/room/room-runtime/api/restricted_current.ignore
@@ -1,3 +1,7 @@
// Baseline format: 1.0
+ChangedType: androidx.room.paging.LimitOffsetDataSource#convertRows(android.database.Cursor):
+ Method androidx.room.paging.LimitOffsetDataSource.convertRows has changed return type from java.util.List<T!> to java.util.List<T>
+
+
RemovedClass: androidx.room.util.CopyLock:
Removed class androidx.room.util.CopyLock
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index 8f29006..24bc4fb 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -236,13 +236,14 @@
package androidx.room.paging {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class LimitOffsetDataSource<T> extends androidx.paging.PositionalDataSource<T> {
- ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.sqlite.db.SupportSQLiteQuery, boolean, java.lang.String!...);
- ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.sqlite.db.SupportSQLiteQuery, boolean, boolean, java.lang.String!...);
- ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.room.RoomSQLiteQuery, boolean, java.lang.String!...);
- ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase, androidx.room.RoomSQLiteQuery, boolean, boolean, java.lang.String!...);
- method protected abstract java.util.List<T!> convertRows(android.database.Cursor);
- method public void loadInitial(androidx.paging.PositionalDataSource.LoadInitialParams, androidx.paging.PositionalDataSource.LoadInitialCallback<T!>);
- method public void loadRange(androidx.paging.PositionalDataSource.LoadRangeParams, androidx.paging.PositionalDataSource.LoadRangeCallback<T!>);
+ ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.room.RoomSQLiteQuery sourceQuery, boolean inTransaction, boolean registerObserverImmediately, java.lang.String... tables);
+ ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.sqlite.db.SupportSQLiteQuery query, boolean inTransaction, java.lang.String... tables);
+ ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.sqlite.db.SupportSQLiteQuery query, boolean inTransaction, boolean registerObserverImmediately, java.lang.String... tables);
+ ctor protected LimitOffsetDataSource(androidx.room.RoomDatabase db, androidx.room.RoomSQLiteQuery query, boolean inTransaction, java.lang.String... tables);
+ method protected abstract java.util.List<T> convertRows(android.database.Cursor cursor);
+ method public void loadInitial(androidx.paging.PositionalDataSource.LoadInitialParams params, androidx.paging.PositionalDataSource.LoadInitialCallback<T> callback);
+ method public void loadRange(androidx.paging.PositionalDataSource.LoadRangeParams params, androidx.paging.PositionalDataSource.LoadRangeCallback<T> callback);
+ property public boolean isInvalid;
}
}
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index 0cdeecd..3e43c71 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -36,7 +36,7 @@
api(project(":sqlite:sqlite-framework"))
api(project(":sqlite:sqlite"))
implementation("androidx.arch.core:core-runtime:2.0.1")
- compileOnly("androidx.paging:paging-common:2.0.0")
+ compileOnly("androidx.paging:paging-common:3.1.0")
compileOnly("androidx.lifecycle:lifecycle-livedata-core:2.0.0")
implementation("androidx.annotation:annotation-experimental:1.1.0-rc01")
compileOnly libs.kotlinStdlib // Due to :annotation-experimental
diff --git a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
deleted file mode 100644
index 81ba417..0000000
--- a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.room.paging;
-
-import android.database.Cursor;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.room.InvalidationTracker;
-import androidx.room.RoomDatabase;
-import androidx.room.RoomSQLiteQuery;
-import androidx.sqlite.db.SupportSQLiteQuery;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * A simple data source implementation that uses Limit & Offset to page the query.
- * <p>
- * This is NOT the most efficient way to do paging on SQLite. It is
- * <a href="http://www.sqlite.org/cvstrac/wiki?p=ScrollingCursor">recommended</a> to use an indexed
- * ORDER BY statement but that requires a more complex API. This solution is technically equal to
- * receiving a {@link Cursor} from a large query but avoids the need to manually manage it, and
- * never returns inconsistent data if it is invalidated.
- *
- * This class is used for both Paging2 and Pagin3 (via its compat API). When used with Paging3,
- * it does lazy registration for observers to be suitable for initialization on the main thread
- * whereas in Paging2, it will register observer eagerly to obey Paging2's strict Data Source
- * rules. (Paging2 does not let data source to possibly return invalidated data).
- *
- * @param <T> Data type returned by the data source.
- *
- * @hide
- */
-@SuppressWarnings("deprecation")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public abstract class LimitOffsetDataSource<T> extends androidx.paging.PositionalDataSource<T> {
- private final RoomSQLiteQuery mSourceQuery;
- private final String mCountQuery;
- private final String mLimitOffsetQuery;
- private final RoomDatabase mDb;
- @SuppressWarnings("FieldCanBeLocal")
- private final InvalidationTracker.Observer mObserver;
- private final boolean mInTransaction;
- private final AtomicBoolean mRegisteredObserver = new AtomicBoolean(false);
-
- protected LimitOffsetDataSource(@NonNull RoomDatabase db,
- @NonNull SupportSQLiteQuery query,
- boolean inTransaction,
- @NonNull
- String... tables) {
- this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, tables);
- }
-
- protected LimitOffsetDataSource(
- @NonNull RoomDatabase db,
- @NonNull SupportSQLiteQuery query,
- boolean inTransaction,
- boolean registerObserverImmediately,
- @NonNull String... tables) {
- this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, registerObserverImmediately,
- tables);
- }
-
- protected LimitOffsetDataSource(
- @NonNull RoomDatabase db,
- @NonNull RoomSQLiteQuery query,
- boolean inTransaction,
- @NonNull String... tables) {
- this(db, query, inTransaction, true /*register registerObserverImmediately*/, tables);
- }
-
- protected LimitOffsetDataSource(
- @NonNull RoomDatabase db,
- @NonNull RoomSQLiteQuery query,
- boolean inTransaction,
- boolean registerObserverImmediately,
- @NonNull String... tables) {
- mDb = db;
- mSourceQuery = query;
- mInTransaction = inTransaction;
- mCountQuery = "SELECT COUNT(*) FROM ( " + mSourceQuery.getSql() + " )";
- mLimitOffsetQuery = "SELECT * FROM ( " + mSourceQuery.getSql() + " ) LIMIT ? OFFSET ?";
- mObserver = new InvalidationTracker.Observer(tables) {
- @Override
- public void onInvalidated(@NonNull Set<String> tables) {
- invalidate();
- }
- };
- if (registerObserverImmediately) {
- registerObserverIfNecessary();
- }
- }
-
- private void registerObserverIfNecessary() {
- if (mRegisteredObserver.compareAndSet(false, true)) {
- mDb.getInvalidationTracker().addWeakObserver(mObserver);
- }
- }
-
- /**
- * Count number of rows query can return
- *
- * @hide
- */
- @SuppressWarnings("WeakerAccess")
- public int countItems() {
- registerObserverIfNecessary();
- final RoomSQLiteQuery sqLiteQuery = RoomSQLiteQuery.acquire(mCountQuery,
- mSourceQuery.getArgCount());
- sqLiteQuery.copyArgumentsFrom(mSourceQuery);
- Cursor cursor = mDb.query(sqLiteQuery);
- try {
- if (cursor.moveToFirst()) {
- return cursor.getInt(0);
- }
- return 0;
- } finally {
- cursor.close();
- sqLiteQuery.release();
- }
- }
-
- @Override
- public boolean isInvalid() {
- registerObserverIfNecessary();
- mDb.getInvalidationTracker().refreshVersionsSync();
- return super.isInvalid();
- }
-
- @NonNull
- @SuppressWarnings("WeakerAccess")
- protected abstract List<T> convertRows(@NonNull Cursor cursor);
-
- @SuppressWarnings("deprecation")
- @Override
- public void loadInitial(@NonNull LoadInitialParams params,
- @NonNull LoadInitialCallback<T> callback) {
- registerObserverIfNecessary();
- List<T> list = Collections.emptyList();
- int totalCount;
- int firstLoadPosition = 0;
- RoomSQLiteQuery sqLiteQuery = null;
- Cursor cursor = null;
- mDb.beginTransaction();
- try {
- totalCount = countItems();
- if (totalCount != 0) {
- // bound the size requested, based on known count
- firstLoadPosition = computeInitialLoadPosition(params, totalCount);
- int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
-
- sqLiteQuery = getSQLiteQuery(firstLoadPosition, firstLoadSize);
- cursor = mDb.query(sqLiteQuery);
- List<T> rows = convertRows(cursor);
- mDb.setTransactionSuccessful();
- list = rows;
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- mDb.endTransaction();
- if (sqLiteQuery != null) {
- sqLiteQuery.release();
- }
- }
-
- callback.onResult(list, firstLoadPosition, totalCount);
- }
-
- @Override
- public void loadRange(@NonNull LoadRangeParams params,
- @NonNull LoadRangeCallback<T> callback) {
- callback.onResult(loadRange(params.startPosition, params.loadSize));
- }
-
- /**
- * Return the rows from startPos to startPos + loadCount
- *
- * @hide
- */
- @SuppressWarnings("deprecation")
- @NonNull
- public List<T> loadRange(int startPosition, int loadCount) {
- final RoomSQLiteQuery sqLiteQuery = getSQLiteQuery(startPosition, loadCount);
- if (mInTransaction) {
- mDb.beginTransaction();
- Cursor cursor = null;
- //noinspection TryFinallyCanBeTryWithResources
- try {
- cursor = mDb.query(sqLiteQuery);
- List<T> rows = convertRows(cursor);
- mDb.setTransactionSuccessful();
- return rows;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- mDb.endTransaction();
- sqLiteQuery.release();
- }
- } else {
- Cursor cursor = mDb.query(sqLiteQuery);
- //noinspection TryFinallyCanBeTryWithResources
- try {
- return convertRows(cursor);
- } finally {
- cursor.close();
- sqLiteQuery.release();
- }
- }
- }
-
- private RoomSQLiteQuery getSQLiteQuery(int startPosition, int loadCount) {
- final RoomSQLiteQuery sqLiteQuery = RoomSQLiteQuery.acquire(mLimitOffsetQuery,
- mSourceQuery.getArgCount() + 2);
- sqLiteQuery.copyArgumentsFrom(mSourceQuery);
- sqLiteQuery.bindLong(sqLiteQuery.getArgCount() - 1, loadCount);
- sqLiteQuery.bindLong(sqLiteQuery.getArgCount(), startPosition);
- return sqLiteQuery;
- }
-}
diff --git a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.kt b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.kt
new file mode 100644
index 0000000..f1203ae
--- /dev/null
+++ b/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:Suppress("DEPRECATION")
+
+package androidx.room.paging
+
+import android.database.Cursor
+import androidx.annotation.RestrictTo
+import androidx.paging.PositionalDataSource
+import androidx.room.InvalidationTracker
+import androidx.room.RoomDatabase
+import androidx.room.RoomSQLiteQuery
+import androidx.sqlite.db.SupportSQLiteQuery
+import java.util.concurrent.atomic.AtomicBoolean
+
+/**
+ * A simple data source implementation that uses Limit & Offset to page the query.
+ *
+ * This is NOT the most efficient way to do paging on SQLite. It is
+ * [recommended](http://www.sqlite.org/cvstrac/wiki?p=ScrollingCursor) to use an indexed
+ * ORDER BY statement but that requires a more complex API. This solution is technically equal to
+ * receiving a [Cursor] from a large query but avoids the need to manually manage it, and
+ * never returns inconsistent data if it is invalidated.
+ *
+ * This class is used for both Paging2 and Paging3 (via its compat API). When used with Paging3,
+ * it does lazy registration for observers to be suitable for initialization on the main thread
+ * whereas in Paging2, it will register observer eagerly to obey Paging2's strict Data Source
+ * rules. (Paging2 does not let data source to possibly return invalidated data).
+ *
+ * @property <T> Data type returned by the data source.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+abstract class LimitOffsetDataSource<T : Any> protected constructor(
+ private val db: RoomDatabase,
+ private val sourceQuery: RoomSQLiteQuery,
+ private val inTransaction: Boolean,
+ registerObserverImmediately: Boolean,
+ vararg tables: String
+) : PositionalDataSource<T>() {
+ private val countQuery = "SELECT COUNT(*) FROM ( " + sourceQuery.sql + " )"
+ private val limitOffsetQuery = "SELECT * FROM ( " + sourceQuery.sql + " ) LIMIT ? OFFSET ?"
+ private val observer: InvalidationTracker.Observer
+ private val registeredObserver = AtomicBoolean(false)
+
+ protected constructor(
+ db: RoomDatabase,
+ query: SupportSQLiteQuery,
+ inTransaction: Boolean,
+ vararg tables: String
+ ) : this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, *tables)
+
+ protected constructor(
+ db: RoomDatabase,
+ query: SupportSQLiteQuery,
+ inTransaction: Boolean,
+ registerObserverImmediately: Boolean,
+ vararg tables: String
+ ) : this(
+ db, RoomSQLiteQuery.copyFrom(query), inTransaction, registerObserverImmediately, *tables
+ )
+
+ protected constructor(
+ db: RoomDatabase,
+ query: RoomSQLiteQuery,
+ inTransaction: Boolean,
+ vararg tables: String
+ ) : this(db, query, inTransaction, true, *tables)
+
+ init {
+ observer = object : InvalidationTracker.Observer(tables) {
+ override fun onInvalidated(tables: Set<String>) {
+ invalidate()
+ }
+ }
+ if (registerObserverImmediately) {
+ registerObserverIfNecessary()
+ }
+ }
+
+ private fun registerObserverIfNecessary() {
+ if (registeredObserver.compareAndSet(false, true)) {
+ db.invalidationTracker.addWeakObserver(observer)
+ }
+ }
+
+ /**
+ * Count number of rows query can return
+ *
+ * @hide
+ */
+ fun countItems(): Int {
+ registerObserverIfNecessary()
+ val sqLiteQuery = RoomSQLiteQuery.acquire(
+ countQuery,
+ sourceQuery.argCount
+ )
+ sqLiteQuery.copyArgumentsFrom(sourceQuery)
+ val cursor = db.query(sqLiteQuery)
+ return try {
+ if (cursor.moveToFirst()) {
+ cursor.getInt(0)
+ } else 0
+ } finally {
+ cursor.close()
+ sqLiteQuery.release()
+ }
+ }
+
+ override val isInvalid: Boolean
+ get() {
+ registerObserverIfNecessary()
+ db.invalidationTracker.refreshVersionsSync()
+ return super.isInvalid
+ }
+
+ protected abstract fun convertRows(cursor: Cursor): List<T>
+
+ @Suppress("deprecation")
+ override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<T>) {
+ registerObserverIfNecessary()
+ val onResultCaller: () -> Unit
+ db.beginTransaction()
+ try {
+ val totalCount = countItems()
+ if (totalCount != 0) {
+ // bound the size requested, based on known count
+ val firstLoadPosition = computeInitialLoadPosition(params, totalCount)
+ val firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount)
+ db.query(getSQLiteQuery(firstLoadPosition, firstLoadSize)).use { cursor ->
+ val rows = convertRows(cursor)
+ db.setTransactionSuccessful()
+ onResultCaller = { callback.onResult(rows, firstLoadPosition, totalCount) }
+ }
+ } else {
+ onResultCaller = { callback.onResult(emptyList(), 0, totalCount) }
+ }
+ } finally {
+ db.endTransaction()
+ }
+ onResultCaller.invoke()
+ }
+
+ override fun loadRange(
+ params: LoadRangeParams,
+ callback: LoadRangeCallback<T>
+ ) {
+ callback.onResult(loadRange(params.startPosition, params.loadSize))
+ }
+
+ /**
+ * Return the rows from startPos to startPos + loadCount
+ *
+ * @hide
+ */
+ @Suppress("deprecation")
+ fun loadRange(startPosition: Int, loadCount: Int): List<T> {
+ val sqLiteQuery = getSQLiteQuery(startPosition, loadCount)
+ try {
+ if (inTransaction) {
+ db.beginTransaction()
+ try {
+ db.query(sqLiteQuery).use { cursor ->
+ val rows = convertRows(cursor)
+ db.setTransactionSuccessful()
+ return rows
+ }
+ } finally {
+ db.endTransaction()
+ }
+ } else {
+ db.query(sqLiteQuery).use { cursor ->
+ return convertRows(cursor)
+ }
+ }
+ } finally {
+ sqLiteQuery.release()
+ }
+ }
+
+ private fun getSQLiteQuery(startPosition: Int, loadCount: Int): RoomSQLiteQuery {
+ val sqLiteQuery = RoomSQLiteQuery.acquire(
+ limitOffsetQuery,
+ sourceQuery.argCount + 2
+ )
+ sqLiteQuery.copyArgumentsFrom(sourceQuery)
+ sqLiteQuery.bindLong(sqLiteQuery.argCount - 1, loadCount.toLong())
+ sqLiteQuery.bindLong(sqLiteQuery.argCount, startPosition.toLong())
+ return sqLiteQuery
+ }
+}
\ No newline at end of file