diff --git a/app/build.gradle b/app/build.gradle index cd88323f13..a716471eb7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -316,12 +316,12 @@ dependencies { def startup_version = "1.1.0" def annotation_version_experimental = "1.2.0" - def core_version = "1.7.0" // 1.8.0-alpha03 + def core_version = "1.7.0" // 1.8.0-alpha05 / 1.9.0-alpha01 def shortcuts_version = "1.0.0" - def appcompat_version = "1.4.1" - def emoji_version = "1.1.0-beta01" - def activity_version = "1.4.0" // 1.5.0-alpha01 - def fragment_version = "1.4.1" // 1.5.0-alpha01 + def appcompat_version = "1.4.1" // 1.6.0-alpha01 + def emoji_version = "1.1.0" // 1.2.0-alpha01 + def activity_version = "1.4.0" // 1.5.0-alpha03 + def fragment_version = "1.4.1" // 1.5.0-alpha03 def webkit_version = "1.4.0" def recyclerview_version = "1.2.1" def coordinatorlayout_version = "1.2.0" @@ -331,10 +331,10 @@ dependencies { def lbm_version = "1.1.0" def swiperefresh_version = "1.2.0-alpha01" def documentfile_version = "1.1.0-alpha01" - def lifecycle_version = "2.4.0" // 2.5.0-alpha01 + def lifecycle_version = "2.4.0" // 2.5.0-alpha03 def lifecycle_extensions_version = "2.2.0" - def room_version = "2.4.1" - def sqlite_version = "2.2.0" + def room_version = "2.4.2" // 2.5.0-alpha01 + def sqlite_version = "2.2.0" // 2.3.0-alpha01 def requery_version = "3.36.0" def paging_version = "2.1.2" // 3.1.0 def preference_version = "1.2.0" diff --git a/app/src/main/java/androidx/room/InvalidationTracker.java b/app/src/main/java/androidx/room/InvalidationTracker.java index fe0ae9a9ae..3a0c5ca530 100644 --- a/app/src/main/java/androidx/room/InvalidationTracker.java +++ b/app/src/main/java/androidx/room/InvalidationTracker.java @@ -104,7 +104,7 @@ public class InvalidationTracker { @SuppressWarnings("WeakerAccess") /* synthetic access */ volatile SupportSQLiteStatement mCleanupStatement; - private ObservedTableTracker mObservedTableTracker; + private final ObservedTableTracker mObservedTableTracker; private final InvalidationLiveDataContainer mInvalidationLiveDataContainer; @@ -115,6 +115,8 @@ public class InvalidationTracker { private MultiInstanceInvalidationClient mMultiInstanceInvalidationClient; + private final Object mSyncTriggersLock = new Object(); + /** * Used by the generated code. * @@ -537,14 +539,13 @@ public class InvalidationTracker { return; } try { - // This method runs in a while loop because while changes are synced to db, another - // runnable may be skipped. If we cause it to skip, we need to do its work. - while (true) { - Lock closeLock = mDatabase.getCloseLock(); - closeLock.lock(); - try { - // there is a potential race condition where another mSyncTriggers runnable - // can start running right after we get the tables list to sync. + Lock closeLock = mDatabase.getCloseLock(); + closeLock.lock(); + try { + // Serialize adding and removing table trackers, this is specifically important + // to avoid missing invalidation before a transaction starts but there are + // pending (possibly concurrent) observer changes. + synchronized (mSyncTriggersLock) { final int[] tablesToSync = mObservedTableTracker.getTablesToSync(); if (tablesToSync == null) { return; @@ -566,10 +567,9 @@ public class InvalidationTracker { } finally { database.endTransaction(); } - mObservedTableTracker.onSyncCompleted(); - } finally { - closeLock.unlock(); } + } finally { + closeLock.unlock(); } } catch (IllegalStateException | SQLiteException exception) { // may happen if db is closed. just log. @@ -789,13 +789,6 @@ public class InvalidationTracker { boolean mNeedsSync; - /** - * After we return non-null value from getTablesToSync, we expect a onSyncCompleted before - * returning any non-null value from getTablesToSync. - * This allows us to workaround any multi-threaded state syncing issues. - */ - boolean mPendingSync; - ObservedTableTracker(int tableCount) { mTableObservers = new long[tableCount]; mTriggerStates = new boolean[tableCount]; @@ -852,7 +845,7 @@ public class InvalidationTracker { } /** - * If this returns non-null, you must call onSyncCompleted. + * If this returns non-null there are no pending sync operations. * * @return int[] An int array where the index for each tableId has the action for that * table. @@ -860,7 +853,7 @@ public class InvalidationTracker { @Nullable int[] getTablesToSync() { synchronized (this) { - if (!mNeedsSync || mPendingSync) { + if (!mNeedsSync) { return null; } final int tableCount = mTableObservers.length; @@ -873,19 +866,8 @@ public class InvalidationTracker { } mTriggerStates[i] = newState; } - mPendingSync = true; mNeedsSync = false; - return mTriggerStateChanges; - } - } - - /** - * if getTablesToSync returned non-null, the called should call onSyncCompleted once it - * is done. - */ - void onSyncCompleted() { - synchronized (this) { - mPendingSync = false; + return mTriggerStateChanges.clone(); } } }