[ANR] Occasionally the lock in AbstractDatabase is never freed and the UI stops responding

Setup: CBL 2.7.1


package com.couchbase.lite;

abstract class AbstractDatabase {

     *  ...

     * Adds a change listener for the changes that occur in the database with an executor on which the changes will be
     * posted to the listener. If the executor is not specified, the changes will be delivered on the UI thread for
     * the Android platform and on an arbitrary thread for the Java platform.
     * @param listener callback
    public ListenerToken addChangeListener(@Nullable Executor executor, @NonNull DatabaseChangeListener listener) {
        Preconditions.checkArgNotNull(listener, "listener");

        synchronized (lock) { // <-- ANR !!
            return addDatabaseChangeListenerSynchronized(executor, listener);


  at com.couchbase.lite.AbstractDatabase.addChangeListener (AbstractDatabase.java:626)
  at com.couchbase.lite.Database.addChangeListener (Database.java:30)
  at com.couchbase.lite.AbstractDatabase.addChangeListener (AbstractDatabase.java:610)
  at com.couchbase.lite.Database.addChangeListener (Database.java:30)
  at com.couchbase.lite.LiveQuery.start (LiveQuery.java:136)
  at com.couchbase.lite.LiveQuery.addChangeListener (LiveQuery.java:113)
  at com.couchbase.lite.AbstractQuery.addChangeListener (AbstractQuery.java:195)
  at com.couchbase.lite.Where.addChangeListener (Where.java:29)
  at com.couchbase.lite.AbstractQuery.addChangeListener (AbstractQuery.java:179)
  at com.couchbase.lite.Where.addChangeListener (Where.java:29)

Occasionally I see this ANR (Application Not Responding) reported. It seems the lock is never freed and the UI stops responding. I wasn’t able to reproduce this issue.

It is not that the log is never freed! It is that it is never seized!

It is likely that your code is performing some other operation that is holding the database lock.

I updated my code and sent an update to a user. I’ll follow up as soon as I know more!

It seems to be fixed but I’m unclear how?!

Below is the old lifecycle of my device. I was never able to run into the issue.

  • (fragment A) user adds many documents at once by clicking a button
  • (fragment A) thread to add document is started and on the main thread the app navigates to fragment B
  • (fragment B) onResume, addChangeListener
  • documents creation is finished
    … so things are overlapping here

I must believe the lifecycle was the same with the user who reported the issue. He did not run into the issue every time but often enough.

Instead of the thread I now use a handler, show a progress bar, wait till the create action is finished, then navigate. User reports that he was no longer able to run into the issue.