【问题标题】:Best practice for opening/closing Realm instances打开/关闭 Realm 实例的最佳实践
【发布时间】:2017-02-19 00:31:20
【问题描述】:

我有一个使用非常常见的设计模式的 Android 应用:

  1. 主要活动本质上是呈现对象列表 - 在小型设备上,它通过托管显示此列表的回收视图的单个片段来实现。在较大的设备上,它托管两个片段,一个具有相同的对象回收视图,另一个将托管单个对象的详细信息,当在列表中选择一个时。
  2. 在较小的设备上,当从列表中进行选择时,会启动一个 Activity,该 Activity 承载一个片段,该片段利用 ViewPager 允许“滑动”通过对象列表,并就地编辑每个对象。

在这两种情况下,用户只能从详细信息片段中进行编辑。

我目前在应用程序类中初始化了我的领域实例,然后在我用来保存一些管理方法的活动基类中检索到默认实例:

public abstract class SingleFragmentActivity extends AppCompatActivity {
    private Realm realm;
    protected abstract Fragment createFragment();

    @LayoutRes
    protected int getLayoutResId() {
        return R.layout.activity_fragment;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        realm = Realm.getDefaultInstance();
        // Initialize ProfileLab
        ProfileLab.get(realm);
        setContentView(getLayoutResId());

        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragment_container);

        if (fragment == null) {
            fragment = createFragment();
            fm.beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if ( realm != null) {
            realm.close();
        }
    }
}

请注意,我将此领域实例存储在静态类“ProfileLab”中:

// Initialize ProfileLab
ProfileLab.get(realm);

然后在更新数据的各种片段中,我正在做类似的事情:

mProfile = ProfileLab.get().getProfile(profileId);
*
* do CRUD activities here for example:
*
    private void deleteProfile() {
        ProfileLab.get().deleteProfile(mProfile);
        mCallbacks.onProfileUpdated(mProfile);
    }

然后在 ProfileLab 中,它看起来像:

公共布尔删除配置文件(配置文件 c){ boolean retVal = true;

try {
    mRealm.beginTransaction();
    c.deleteFromRealm();

} catch (Exception e) {
    retVal = false;
} finally {
    if ( mRealm != null ) {
        if (retVal) {
            mRealm.commitTransaction();
        } else {
            mRealm.cancelTransaction();
        }

    }
}
return (retVal);

}

我的问题 - 在整个应用程序的使用过程中,基本上保持 Realm 实例处于打开状态是一个问题吗?我在文档中注意到了这一段:

如果你从没有 Looper 的线程中获取 Realm 实例 附加,那么来自此类实例的对象将不会被更新,除非 调用 waitForChange() 方法。需要注意的是 必须保留旧版本的数据是昂贵的 内存和磁盘空间,成本随着数量的增加而增加 保留的版本和最新版本之间的版本。这就是为什么它 完成后立即关闭 Realm 实例很重要 它在线程中。

问题是,我还没有“完成”,因为这是在 UI 线程上,它显然在我的应用程序的整个生命周期中运行。

我不能仅仅为了原子更新而真正打开/关闭领域实例,因为我需要使用初始查询的结果来显示要从中选择编辑的对象列表 - 当我最初尝试这样做时(我在 ProfileLab 本身的每个方法中打开/关闭了领域对象)我在回收器适配器中收到一个错误,表明领域已关闭...

显示使用回收器视图的示例代码显示了在单个活动级别检索/使用/关闭的领域,如果我在说两个简单的活动(托管 RecyclerView 和托管 ViewPager)之间这样做,数据是否会更新互相反映?

【问题讨论】:

  • 如果我使用多个很少见的活动,那么我引用计数打开活动的数量,如果计数达到 0,则关闭领域(请参阅example
  • 感谢您的反馈,我会查看您的示例。

标签: android android-fragments realm


【解决方案1】:

建议在 try/catch 块中打开和关闭领域。例如:

try {
 Realm realm = Realm.getDefaultInstance();
 //Use the realm instance

}catch(Exception e){
  //handle exceptions
}finally {
    realm.close();
}

这是一个基本的例子。如果能在AsyncTask内关闭,就更好了。

official documentation 表示如果你使用 minSdkVersion >= 19Java >= 7,你不会手动关闭它。

try (Realm realm = Realm.getDefaultInstance()) {
// No need to close the Realm instance manually
}

【讨论】:

    【解决方案2】:

    Realm 将自动使 Looper 线程上的 Realms 保持最新。文档中的那一行主要是指后台线程。所以你的代码很好,即使onDestroy 可能不会被调用。

    您还可以阅读文档中的这些相关部分:

    https://realm.io/docs/java/latest/#closing-realms https://realm.io/docs/java/latest/#realm-instance-lifecycle

    【讨论】:

    • ` CommitLog tmpCommit = realm.where(CommitLog.class).equalTo("conversationId", cache.getConversationId()).findFirst();领域.close(); if (tmpCommit != null) { `我需要知道 tmpCommit != null 这部分在领域关闭发生后有数据
    猜你喜欢
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 2010-10-06
    • 2011-10-28
    • 2010-09-10
    • 2011-10-11
    相关资源
    最近更新 更多