diff --git a/app/build.gradle b/app/build.gradle index 50dd4f4342..7b70f276b6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -235,11 +235,11 @@ configurations.all { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - def annotation_version = "1.1.0-beta01" - def core_version = "1.5.0-beta02" + def annotation_version = "1.1.0-rc01" + def core_version = "1.5.0-beta03" def appcompat_version = "1.3.0-beta01" - def activity_version = "1.2.0" - def fragment_version = "1.3.0" + def activity_version = "1.2.1" + def fragment_version = "1.3.1" def webkit_version = "1.4.0" def recyclerview_version = "1.2.0-beta02" def coordinatorlayout_version = "1.1.0" @@ -252,7 +252,7 @@ dependencies { def lifecycle_version = "2.3.0" def lifecycle_extensions_version = "2.2.0" def sqlite_version = "2.1.0" - def room_version = "2.3.0-beta02" + def room_version = "2.3.0-beta03" def paging_version = "2.1.2" // 3.0.0-alpha11 def preference_version = "1.1.1" def work_version = "2.5.0" diff --git a/app/src/main/java/androidx/room/ExperimentalRoomApi.java b/app/src/main/java/androidx/room/ExperimentalRoomApi.java index 7396429d1b..729a4a9bf6 100644 --- a/app/src/main/java/androidx/room/ExperimentalRoomApi.java +++ b/app/src/main/java/androidx/room/ExperimentalRoomApi.java @@ -26,4 +26,4 @@ import java.lang.annotation.Target; */ @Target({ElementType.METHOD}) @RequiresOptIn() -@interface ExperimentalRoomApi {} +public @interface ExperimentalRoomApi {} diff --git a/app/src/main/java/androidx/room/paging/LimitOffsetDataSource.java b/app/src/main/java/androidx/room/paging/LimitOffsetDataSource.java index 0e4b5edf64..d3513473af 100644 --- a/app/src/main/java/androidx/room/paging/LimitOffsetDataSource.java +++ b/app/src/main/java/androidx/room/paging/LimitOffsetDataSource.java @@ -28,6 +28,7 @@ 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. @@ -38,6 +39,11 @@ import java.util.Set; * 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 Data type returned by the data source. * * @hide @@ -52,14 +58,40 @@ public abstract class LimitOffsetDataSource extends androidx.paging.Positiona @SuppressWarnings("FieldCanBeLocal") private final InvalidationTracker.Observer mObserver; private final boolean mInTransaction; + private final AtomicBoolean mRegisteredObserver = new AtomicBoolean(false); - protected LimitOffsetDataSource(RoomDatabase db, SupportSQLiteQuery query, - boolean inTransaction, String... tables) { + protected LimitOffsetDataSource(@NonNull RoomDatabase db, + @NonNull SupportSQLiteQuery query, + boolean inTransaction, + @NonNull + String... tables) { this(db, RoomSQLiteQuery.copyFrom(query), inTransaction, tables); } - protected LimitOffsetDataSource(RoomDatabase db, RoomSQLiteQuery query, - boolean inTransaction, String... 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; @@ -71,7 +103,15 @@ public abstract class LimitOffsetDataSource extends androidx.paging.Positiona invalidate(); } }; - db.getInvalidationTracker().addWeakObserver(mObserver); + if (registerObserverImmediately) { + registerObserverIfNecessary(); + } + } + + private void registerObserverIfNecessary() { + if (mRegisteredObserver.compareAndSet(false, true)) { + mDb.getInvalidationTracker().addWeakObserver(mObserver); + } } /** @@ -81,6 +121,7 @@ public abstract class LimitOffsetDataSource extends androidx.paging.Positiona */ @SuppressWarnings("WeakerAccess") public int countItems() { + registerObserverIfNecessary(); final RoomSQLiteQuery sqLiteQuery = RoomSQLiteQuery.acquire(mCountQuery, mSourceQuery.getArgCount()); sqLiteQuery.copyArgumentsFrom(mSourceQuery); @@ -98,17 +139,20 @@ public abstract class LimitOffsetDataSource extends androidx.paging.Positiona @Override public boolean isInvalid() { + registerObserverIfNecessary(); mDb.getInvalidationTracker().refreshVersionsSync(); return super.isInvalid(); } + @NonNull @SuppressWarnings("WeakerAccess") - protected abstract List convertRows(Cursor cursor); + protected abstract List convertRows(@NonNull Cursor cursor); @SuppressWarnings("deprecation") @Override public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback callback) { + registerObserverIfNecessary(); List list = Collections.emptyList(); int totalCount = 0; int firstLoadPosition = 0;