在Android中使用Singleton模式的领域:优点和缺点

时间:2018-03-21 06:33:09

标签: android singleton realm realm-mobile-platform

您好我已经完成了Realm中的最佳实践,根据它,处理Realm实例的最佳方法是使用onCreate()在Activity的relam = Realm.getDefaultInstance()方法中打开realm实例并将其关闭onDestroy()使用realm.close()

但是目前我的代码中有以下单例结构。我需要了解以下单例结构的优缺点,而不是领域文档中提出的最佳实践。

这是我的代码:方法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()在我的活动,服务,意图服务中创建领域实例,然后继续进行交易。在我的所有活动onDestroy()方法中,我使用RealmManager.closeRealm()关闭领域。所以我的问题是,如果在Activity RealmManager.closeRealm()中调用的onDestroy()会影响在Service中执行的任何事务吗?

这是我的代码:方法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才会被销毁,并且realm实例将被销毁。或者我需要在应用程序级别关闭realm实例(我不确定是否可以在应用程序级别关闭实例)。

在方法1和方法2中哪一个更好。或者使用onCreate()在活动的relam = Realm.getDefaultInstance()方法中打开领域实例并使用{在onDestroy()中关闭它更好{1}}。

1 个答案:

答案 0 :(得分:0)

Realm很难在&#34;单身经理下使用&#34;因为Realm.getDefaultInstance()可能看起来像是你得到的东西是单身&#34;但它确实不是。领域的实例是thread-localreference-counted,每次调用getInstance()都会增加引用计数,而close()会减少引用计数。

我已经多次说过open()会有更好的名字,但我得出的结论太晚了:)

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

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

  • 您希望在1个异步事务中执行每个1个操作的硬编码,因此您无法在后台线程中使用此东西

为了使一个可以在任何线程上调用的域管理器,并且UI线程在后台线程使用同步事务时使用异步事务,您需要使用method like this

此外,您需要跟踪该给定线程的开放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);
        }
    }

有了这样的课程,你可以这样做:

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,但它从未真正流行过。如果好奇,请查看来源。