androidbash
androidbash

Reputation: 430

Realm with Singleton Pattern in Android : Correct structure or not?

Currently I have following singleton structure in my code for managing Realm transactions. I need to know the pros and cons of the following singleton structure. With this approach i will be calling updateClockModel() as RealManager.getInstance().updateClockModel(...) from all my activities and fragments.

public class RealmManager {

private static final String TAG = "RealmManager";
private static RealmManager mInstance = null;
private final ThreadLocal<Realm> localRealm = new ThreadLocal<>();

public static RealmManager getInstance() {
    if (mInstance == null)
        mInstance = new RealmManager();
    return mInstance;
}

public Realm openLocalInstance() {
    Realm realm = Realm.getDefaultInstance();
    if (localRealm.get() == null) {
        localRealm.set(realm);
    }
    return realm;
}

public Realm getLocalInstance() {
    Realm realm = localRealm.get();
    if (realm == null) {
        throw new IllegalStateException("No open Realms were found on this thread.");
    }
    return realm;
}

public void closeLocalInstance() {
    Realm realm = localRealm.get();
    if (realm == null) {
        throw new IllegalStateException(
                "Cannot close a Realm that is not open.");
    }
    realm.close();
    if (Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
        localRealm.set(null);
    }
}

protected RealmManager() {
}

public void updateClockModel(ClockRLM clockRLM, OnRealmDatabaseListener mRealmListener) {
    Realm mRealm = openLocalInstance();

    mRealm.executeTransactionAsync(realm -> {
        RealmResults<ClockRLM> result = realm.where(ClockRLM.class).equalTo("timeStamp", clockRLM.getTimeStamp()).findAll();
        for (ClockRLM clockRLM1 : result) {
            clockRLM1.setUploadedSuccess(true);
        }
    }, new Realm.Transaction.OnSuccess() {
        @Override
        public void onSuccess() {
            Log.d("Clocke ", "inserted TimeStamp " + clockRLM.getTimeStamp());
            if (mRealmListener != null)
                mRealmListener.isDatabaseOperationSuccess(clockRLM, true);

            closeLocalInstance();
        }
    }, new Realm.Transaction.OnError() {
        @Override
        public void onError(Throwable error) {
            if (mRealmListener != null)
                mRealmListener.isDatabaseOperationSuccess(clockRLM, false);
            closeLocalInstance();
        }
    });
}

public void addClockModel(ClockRLM clockRLM, OnRealmDatabaseListener mRealmListener) {
    Realm mRealm = openLocalInstance();

    mRealm.executeTransactionAsync(realm -> realm.copyToRealm(clockRLM), new Realm.Transaction.OnSuccess() {
        @Override
        public void onSuccess() {
            Log.d("Clocke ", "Inserted TimeStamp " + clockRLM.getTimeStamp());
            if (mRealmListener != null)
                mRealmListener.isDatabaseOperationSuccess(clockRLM, true);
            closeLocalInstance();
        }
    }, new Realm.Transaction.OnError() {
        @Override
        public void onError(Throwable error) {
            closeLocalInstance();
        }
    });
  }
}

Upvotes: 2

Views: 487

Answers (1)

EpicPandaForce
EpicPandaForce

Reputation: 81539

It would work, except those methods that do writes cannot be executed on background threads - only on ui thread - so I'd add something like following method

private void executeInTransaction(Realm.Transaction transaction) {
    try {
        Realm realm = openLocalInstance();
        if(!realm.isAutoRefresh()) {
            try {
                boolean wasInTransaction = realm.isInTransaction();
                if(!wasInTransaction) {
                    realm.beginTransaction();
                }
                transaction.execute(realm);
                if(!wasInTransaction) {
                    realm.commitTransaction();
                }
            } catch(Throwable e) {
                if(realm.isInTransaction()) {
                    realm.cancelTransaction();
                }
            }
        } else {
            realm.executeTransactionAsync(transaction);
        }
    } finally {
        closeLocalInstance();
    }
}

This way you can do batch background operations with manual transaction opening + execute async writes from UI thread.

You need a bit of tweaking to add a "success/failure" listener but the basics are there.

Upvotes: 1

Related Questions