Over a million developers have joined DZone.

Determining Status of a Replication in Couchbase Lite

DZone 's Guide to

Determining Status of a Replication in Couchbase Lite

Couchbase Lite runs replications with background threads. It's very helpful, but you must be careful to avoid mistakes in detecting the state of a replication.

· Database Zone ·
Free Resource

Couchbase Lite runs replications (syncs) using background threads. Starting and stopping replications doesn’t happen synchronously. This can lead to mistakes in detecting the state of a replication.

The Replication class has, depending on the platform, either a running property or a convenience routine like isRunning(). This is a lightweight way of checking the status of a replication.

Using it can lead to unexpected results, though. For example, I recently wrote a utility that uses continuous replications. I have a toggle button to start and stop them. It’s tempting to use isRunning to update the button state. Turns out, this is a bad idea. That's not surprising, given changes happen in the background, but easy to overlook.

Instead, the preferred approach uses a change listener. Here’s an example.

We have two classes. The database helper class wraps some standard operations for simplicity. I added an interface to employ a callback pattern. The client class has to implement it. The helper class digests the Couchbase Lite change notification before passing anything to the client. This gives a nice separation of concerns.

The code listings below are outlines. They only show essentials. Let’s look at the helper class first.

public class DBHelper implements Replication.ChangeListener {
  private boolean replicationActive = false;
  private List stateListeners = new ArrayList<>();

  public interface ReplicationStateListener {
    void onChange(boolean isActive);

  public void startReplication(URL gateway, boolean continuous) {


  public void stopReplication() {

  public void addReplicationStateListener(ReplicationStateListener listener) {

  public void removeReplicationStateListener(ReplicationStateListener listener) {

  // Replication.ChangeListener
  public void changed(Replication.ChangeEvent changeEvent) {
    if (changeEvent.getError() != null) {
      Throwable lastError = changeEvent.getError();

      // React to the error


    if (changeEvent.getTransition() == null) return;

    ReplicationState dest = changeEvent.getTransition().getDestination();

    replicationActive = ((dest == ReplicationState.STOPPING || dest == ReplicationState.STOPPED) ? false : true);

    stateListeners.forEach(listener -> listener.onChange(replicationActive));

We see that DBHelper implements the Replication.ChangeListener interface. This is an interface defined by Couchbase Lite. In startReplication, we add this listener to the replication. It has one method to override: changed. The ChangeEvent passed in can have several different values. In the example, I check for errors first and notify the user if one occurs. Otherwise I check to see if this is a replication state transition event. The destination state can be one of INITIAL, RUNNING, IDLE, OFFLINE, STOPPING, or STOPPED.

In this case, I just want to know if the replication is shutting down, so I simplify the return value. I allow clients to register more than one listener, so the last bit of code loops over all the callbacks and invokes them.

The client class is even simpler. I have the class implement the needed interface from the helper class. Just register the listener during instance construction, and have onChange do whatever you need in the UI.

public class Client implements DBHelper.ReplicationStateListener {
  private DBHelper service = DBHelper.getInstance();

  public Client() {


  // DBHelper.ReplicationStateListener
  public void onChange(boolean isActive) {
    // Code to handle the change

This code is drawn from a tool I built. Read about the tool itself in this post. You can find the source code on GitHub here.

couchbase lite ,database ,replications ,status check

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}