深入了解Realm如何运作?

时间:2016-08-01 09:59:01

标签: java android realm

Q1:请告诉我以下两种implementation方式之间的区别(关于get realm instance)。我想知道哪一个更快,内存更轻,推荐什么?

1。设置并获取领域为默认值(使用特定配置)

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.直接从配置获取领域

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:在我的应用程序中,现在我们考虑两种实现方式。

1:每当我们需要使用Database(在工作线程和UI线程中)执行某些操作时,我们都会创建一个新的Realm实例,并在任务完成时关闭它。

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

请解释一下每个方法的优缺点以及推荐的方法(我的应用程序使用Service处理数据库和网络连接)

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

如果在执行事务时出现问题(例如没有响应或抛出某些异常),将会发生什么?

1 个答案:

答案 0 :(得分:4)

注意:我不是官方的Realm人员,但我现在已经使用Realm了一段时间。

这是TL;DR version

1。)值得注意的是:

  • 应该只在整个应用程序中使用相同的RealmConfiguration访问给定的Realm文件,因此这里的 第一个 解决方案更可取(不要创建每个领域的新配置。)
  • Realm.compactRealm(RealmConfig)仅在任何线程上没有打开的Realm实例时有效。因此,无论是在应用程序启动时,还是在应用程序完成时(我个人发现它使启动速度变慢,因此当我的活动计数达到compactRealm()时我会调用0,我使用保留的片段来管理Realm.getInstance()活动 - 但那只是我)。

2。)值得注意的是,0在第一次调用时会创建一个线程本地缓存(缓存在属于同一个线程的Realm实例之间共享,并递增计数器以指示Realm实例的数量是多少在该给定线程上打开。当该计数器在所有实例上调用realm.close()后达到Realm时,缓存将被清除。

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

在后台线程上打开的Realm实例上调用Realm realm = null; try { realm = Realm.getDefaultInstance(); //do database operations } finally { if(realm != null) { realm.close(); } } 非常重要

try(Realm realm = Realm.getDefaultInstance()) {
    //do database operations
}

或API 19 +:

realm.close()
  • 当您在特定Realm实例上调用open/close时,它会使属于它的结果和对象无效。因此,对onCreate()onDestroy()中的RealmConfiguration realmConfig = new RealmConfiguration.Builder(appContext).build()领域都有意义,或者在应用程序中打开它并在UI线程上共享相同的UI线程Realm实例。

  • (关闭UI线程上的Realm实例并不重要,除非您打算在所有这些实例关闭后压缩它,但必须关闭后台线程上的Realm实例。)

注意:如果您在Application.onCreate()中调用getFilesDir(),则在某些设备上调用null会失败,因为RealmConfiguration可以返回executeTransactionAsync(),所以它是最好在第一个活动开始后初始化RealmAsyncTask

考虑到所有这些,2)的答案是:

  • 虽然我个人为UI线程创建了一个Realm实例,但您仍然需要为任何后台线程打开(并关闭!)一个新的Realm实例。

  • 我使用Realm的单个实例作为UI线程,因为它更容易注入这种方式,并且因为RealmResults<T>的{​​{1}}在基础Realm实例关闭的同时被取消它仍然在执行,所以我真的不希望这种情况发生。 :)

  • 不要忘记,您需要UI线程上的Realm实例才能从领域查询中显示copyFromRealm()(除非您打算使用IntentService,这会使一切都使用更多内存,并且通常较慢)

  • realm.cancelTransaction()的工作方式与普通的后台线程类似,因此您也应该关闭那里的realm实例。

无论是同一个Realm实例还是另一个(只确保你在该给定线程上有一个Realm实例),这两个繁重的任务都可以工作,但我建议一个接一个地连续执行这些任务。

如果在交易期间有异常,您应该调用realm.executeTransaction(new Realm.Transaction() { ... });(文档说明开始/提交,但它总是忘记取消)。

如果您不想手动管理开始/提交/取消,则应使用executeTransaction(),因为它会自动为您调用begin / commit / cancel。我个人在任何地方使用docker-php-ext-install ftp因为它很方便。