2016-08-01 37 views
3

Q1:请让我知道以下两种方式implementation之间有什么不同(约获得realm instance)。我想知道哪一个更快,内存更轻,建议什么?深入了解Realm的工作原理?

1.设置和获取境界为默认值(具体配置)从配置直接

public Realm getCustomRealm(Context context) { 
     if (!Utils.isStringHasText(databaseName)) { 
      databaseName = DbManager.getInstance().getCurrentDb(); 
     } 
     // get config 
     RealmConfiguration config = getRealmConfigByDBName(context, databaseName); 
     Realm.compactRealm(config); 
     return Realm.getInstance(config); 
    } 

Q2

private void setupCustomRealm() { 
     if (!Utils.isStringHasText(databaseName)) { 
      databaseName = DbManager.getInstance().getCurrentDb(); 
     } 
     // get config 
     RealmConfiguration config = getRealmConfigByDBName(databaseName); 
     Realm.setDefaultConfiguration(config); 
     Realm.compactRealm(config); 

    } 

public Realm getCustomRealm() { 
     if (firstTime) { 
      setupCustomRealm(); 
     } 
     return Realm.getDefaultInstance(); 
} 

2。获得境界:在我的应用程序,现在我们考虑两种实施方式。

1:我们每次需要对数据库(在工作线程和UI线程中)都做一些事情时创建一个新的Realm实例,并在任务完成时关闭它。

2:我们只创建一个Realm实例并让它与应用程序一起生存,退出应用程序时我们关闭上面的实例。

(使用服务来处理数据库和网络连接我的应用程序),请解释一下我的优势和每一个和方式的缺点,建议

如果我有2个繁重的任务(需要很长的时间来完成它的交易),在一个Realm实例中执行2个任务和在2个独立的线程中执行2个Realm实例之间的区别(我的意思是一个线程有一个Realm实例,实例将执行上面两个任务中的一个),以及哪一个更安全并且更快。

如果在执行交易(例如无响应或抛出一些例外)

+0

当我用午餐(回复钩评论) – EpicPandaForce

+0

大做,我会回答这个问题!我在等你的答案! –

+0

我还链接SO境界文档,因为他们整齐,我保留了一些它的最新和东西:http://stackoverflow.com/documentation/android/3187/realm#t=201608011053013386746 – EpicPandaForce

回答

4

注意有一个问题会发生什么:我不是一个官方的境界的人,但我一直在使用的境界,而现在。

这里有一个TL;DR version


1)值得注意的几件事情:

  • 给定的领域文件应该只在整个应用程序相同的RealmConfiguration访问,所以第一个这里的解决方案是可取的(不要为每个领域创建一个新的配置)。
  • Realm.compactRealm(RealmConfig)只有在有时才有效任何线程上都没有打开的Realm实例。因此,无论是在应用程序启动时还是在应用程序结束时(个人而言,我发现启动速度较慢,所以当我的活动计数达到0时我拨打compactRealm(),我用一个保留的片段来管理该活动 - 但这只是我) 。

2)值得一提的是Realm.getInstance()在第一次调用创建一个线程本地高速缓存(缓存属于同一个线程领域实例之间共享,并增加一个计数器来显示许多领域实例如何打开在给定的线程。由于在所有实例上调用realm.close()而导致该计数器达到0时,缓存被清除。

值得注意的是Realm实例是线程受限的,因此您需要在任何使用它的线程上打开新的Realm。这意味着如果您在IntentService中使用它,则需要打开一个新的Realm(因为它位于后台线程中)。

它是极其重要在后台线程上打开的Realm实例上调用realm.close()

Realm realm = null; 
try { 
    realm = Realm.getDefaultInstance(); 
    //do database operations 
} finally { 
    if(realm != null) { 
     realm.close(); 
    } 
} 

或者API 19+:

try(Realm realm = Realm.getDefaultInstance()) { 
    //do database operations 
} 
  • 当你调用一个特定领域实例realm.close(),它属于它的结果和对象无效。因此,open/close活动onCreate()onDestroy()中的领域都是有意义的,或者在应用程序中打开它并在UI线程上共享相同的UI线程Realm实例以进行查询。

  • (这并不重要,除非你打算后,他们都压缩它关闭关闭UI线程上的领域实例,但你必须密切领域实例的后台线程)。

注:调用RealmConfiguration realmConfig = new RealmConfiguration.Builder(appContext).build()如果您在Application.onCreate()调用它可以在某些设备发生故障,因为getFilesDir()可以返回null,所以最好以初始化RealmConfiguration第一个活动开始后进行。

有了这些想法,回答2):

  • 虽然我个人创造境界UI线程的单个实例,你仍然需要打开(和关闭)!任何后台线程的新Realm实例。

  • 我用领域的单个实例的UI线程,因为它更容易注入这种方式,还因为executeTransactionAsync()的,如果同时它还是执行底层领域实例关闭RealmAsyncTask被取消,所以我没有真的想要这样的事情发生。 :)

  • 不要忘记,你需要在UI线程上一个领域实例显示来自境界查询RealmResults<T>(除非你打算使用copyFromRealm()这使得一切使用更多的内存,并且通常较慢)

  • IntentService就像普通的后台线程一样工作,所以你也应该关闭领域实例。

两个任务重工作,无论是在同一领域实例或者其他(只要确保你有一个给定的线程上的领域实例),但我建议你连续地执行这些任务,一前一后。

如果在交易过程中出现异常,您应该拨打电话realm.cancelTransaction()(文档说开始/提交,但它总是忘记取消)。

如果您不想手动管理开始/提交/取消,你应该使用realm.executeTransaction(new Realm.Transaction() { ... });,因为它会自动调用开始/提交/取消你。我个人使用executeTransaction()因为它很方便。

+0

我已经也给出了对[Github上境界的Java问题]短,更简洁的答案(https://github.com/realm/realm-java/issues/3229#issuecomment-236552238) – EpicPandaForce

+0

你知道会抛出什么样的异常当我们试图压缩领域而其他实例还没有关闭? –

+0

如果我没有记错,它不会抛出异常,它只是返回false。必须注意的是,加密的Realms不能被压缩。 'compactRealm()'调用似乎消耗了任何异常,并且如果您在代码中添加了'RealmLog.add(new Logger(){...})',则可以看到该消息。 – EpicPandaForce