Android 中单例模式的领域:优点和缺点

Realm with Singleton Pattern in Android: Pros and Cons

嗨,我已经了解了 Realm 中的最佳实践,根据它,处理 Realm 实例的最佳方法是使用 [=14] 在 Activity 的 onCreate() 方法中打开一个领域实例=] 并使用 realm.close()onDestroy() 中关闭它。

但目前我的代码中有以下单例结构。我需要了解以下单例结构相对于领域文档中建议的最佳实践的优缺点。

这是我的代码:方法 1

public class RealmManager {
private static final String TAG = "RealmManager";

private RealmAsyncTask transactionManager;
private static RealmManager mInstance = null;

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

private Realm mRealm;

protected RealmManager() {
    mRealm = Realm.getDefaultInstance();
}

public void saveOrUpdateChatChannel(ChatChannel channel) {
    mRealm = Realm.getDefaultInstance();
    mRealm.executeTransactionAsync(new Realm.Transaction() {
        @Override
        public void execute(@NonNull Realm bgRealm) {
            bgRealm.copyToRealmOrUpdate(channel);
        }
    }, new Realm.Transaction.OnError() {
        @Override
        public void onError(Throwable error) {
            Log.e(TAG,"Failed to update Channel");
        }
    });
}

public void deleteChatChannel(String channelID, OnRealmDatabaseListener mRealmListener) {
    mRealm = Realm.getDefaultInstance();

    mRealm.executeTransactionAsync(new Realm.Transaction() {
        @Override
        public void execute(@NonNull Realm realm) {
            RealmResults<ChatChannel> result = realm.where(ChatChannel.class).equalTo("channelId", channelID).findAll();
            result.deleteAllFromRealm();
        }
    }, new Realm.Transaction.OnSuccess() {
        @Override
        public void onSuccess() {
            if (mRealmListener != null)
                mRealmListener.isDatabaseOperationSuccess(channelID, true);
        }
    }, new Realm.Transaction.OnError() {
        @Override
        public void onError(@NonNull Throwable error) {

        }
    });
}

public void closeRealm() {
    if (mRealm != null) {
        mRealm.close();
    }
    if (transactionManager != null) {
        transactionManager.cancel();
    }
  }

}

所以在方法 1 中,我将使用 RealmManager.getInstance() 在我的活动、服务、意图服务中创建领域实例,然后继续进行交易。在我所有的 Activity onDestroy() 方法中,我使用 RealmManager.closeRealm() 关闭领域。所以我的问题是,如果在 Activity onDestroy() 中调用的 RealmManager.closeRealm() 会影响在服务中执行的任何事务吗?

这是我的代码:方法 2

public class RealmManager {

private static RealmManager mInstance = null;

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

private Realm mRealm;

protected RealmManager(){
    mRealm = Realm.getDefaultInstance();
}

public void addClockModel(ClockRLM clockRLM,OnRealmDatabaseListener mRealmListener){

    RealmAsyncTask transactionManager = 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);
            if (transactionManager != null)
                transactionManager.cancel();
        }
    }, new Realm.Transaction.OnError() {
        @Override
        public void onError(Throwable error) {
            if (transactionManager != null)
                transactionManager.cancel();
        }
    });
  }
}

所以在方法 2 中,我将使用 RealmManager.getInstance() 在我的活动、服务、意图服务中创建领域实例,然后继续进行交易。如果我使用方法 2,我不确定在哪里关闭领域。如果我不在任何地方关闭它并且仅当应用程序关闭时,RealmManager 被销毁并且领域实例将被销毁怎么办。或者我需要在应用程序级别关闭领域实例(我不确定我们是否可以在应用程序级别关闭实例)。

方法 1 和方法 2 中哪一个更好。还是使用 relam = Realm.getDefaultInstance() 在 Activity 的 onCreate() 方法中打开领域实例并在 onDestroy() 使用 realm.close()

Realm 在 "singleton manager" 下很难使用,因为 Realm.getDefaultInstance() 可能看起来像是 "singleton",但实际上不是。 Realm 的实例是 thread-localreference-counted,每次调用 getInstance() 都会增加一个引用计数,而 close() 会减少它。

我已经说过几次 open() 会是一个更好的名字,但我得出这个结论太晚了:)

首先,你的Singleton方法不好的原因是:

  • 只能从第一个调用 RealmManager.getInstance() 的线程调用方法,这应该是 UI 线程(但不保证)

  • 你hard-code你想在 1 个异步事务中执行每个 1 个操作,所以你不能在后台线程上过多地使用这个东西

为了创建可以在任何线程上调用的领域管理器,并且 UI 线程使用异步事务而后台线程使用同步事务,您需要使用

此外,您还需要跟踪该给定线程的打开 Realm 实例,以便您可以在任何需要的地方访问它,而无需增加引用计数。

public class RealmManager {
    private final ThreadLocal<Realm> localRealm = new ThreadLocal<>();

    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);
        }
    }

有了这样的 class,你可以这样做:

try {
    realmManager.openLocalInstance();
    // Realm is open and can be accessed on this thread with `realmManager.getLocalInstance()`
    // also all your methods in the RealmManager can use `getLocalInstance()`
} finally {
    realmManager.closeLocalInstance();
}


不久前我还创建了一个库 wraps Realm in such a way that it eliminates the need for manual reference counting,但它从未真正流行起来。如果好奇,请查看来源。