如何使用 RxJava 和 Realm 构建本地数据源?

How do you structure a local data source using RxJava and Realm?

我非常兴奋 Realm 现在支持引入了 asFlowable 功能的 RxJava 2,所以感谢为此做出贡献的任何人。

我面临的问题是如何最好地管理本地数据源单例中领域实例的生命周期class。我的本地数据源类似于 Android 架构示例 here。在 RxJava 的 Realm 示例中,它们在 onCreate 中实例化一个 realm 实例,并在 activity 的 onDestroy 中关闭它。但是,由于我的本地数据源是单例,所以我不会有这些生命周期事件来实例化和关闭实例。

问题是:我应该在每次创建单例时实例化一个领域实例并仅在销毁单例时关闭它,还是应该在 activity/fragment 中实例化一个领域实例,将其注入本地数据源,然后在 activity/fragment? 欢迎任何其他建议。谢谢!

请注意,不关闭 UI 线程上的 Realm 文件并不一定危险,因为它会自动保持最新状态。唯一的缺点是您不能再使用要求文件完全关闭的功能,例如删除它。

就我个人而言,我认为生命周期事件确实属于模型层,因为您经常需要它们来处理其他事情,例如控制传感器 and/or GPS。

特别是现在 Architecture Components 已经达到 1.0,我建议将 LifecycleObservable 视为控制 Realm 实例的方法:https://developer.android.com/topic/libraries/architecture/lifecycle.html

they instantiate a realm instance in the onCreate and close it in the onDestroy of the activity

那是 UI 线程领域。

inject it into the local data source

您收到的 Realm 实例是线程本地引用计数实例,而不是 "thread-safe" 单例。所以你可能不应该直接注入 Realm,因为那样它就会被限制在一个给定的线程中。


通常 UI 线程 Realm 可以由 ViewModelretained fragmentonCreate()/onDestroy() 等管理,因为 Realm 只提供通知如果 RealmResults 有效,则表示 Realm 实例已打开。

所以要在任何线程上公开 RealmResults,不知道它是一个 RealmResults,您需要做

public Flowable<List<ChatsModel>> getAllChatsData(Realm realm) {
    RealmQuery<ChatsModel> query = realm.where(ChatsModel.class);
    if(realm.isAutoRefresh()) {
        return query.findAllAsync().asFlowable().filter(RealmResults::isLoaded);
    } else {
        return Flowable.just(query.findAll());
    } 
}

如您所见,它接收 Realm 实例作为其输入。现在,如果你想删除那个参数,你需要隐藏你从本地数据源公开的任何内容的引用计数,我个人认为 LiveData 是最好的选择——因为它有onActive()/onInactive() 个回调。

public class RealmLiveData<T extends RealmModel> extends MutableLiveData<List<T>> {
    public interface QueryDefinition<M extends RealmModel> {
        RealmResults<M> createResults(Realm realm);
    }

    private final QueryDefinition<T> queryDefinition;

    public RealmLiveData(QueryDefinition<T> query) {
        this.queryDefinition = query;
        // TODO: handle realm config other than DefaultConfig if needed
    }

    Realm realm;
    RealmResults<T> results;
    RealmChangeListener<RealmResults<T>> realmChangeListener = new RealmChangeListener<RealmResults<T>>() {
        @Override
        public void onChange(RealmResults<T> results) {
            if(results.isLoaded()) {
                setValue(results);
            }
        }
    }

    @Override
    public void onActive() {
        realm = Realm.getDefaultInstance();
        results = queryDefinition.createResults(realm);
        results.addChangeListener(realmChangeListener);
    }

    @Override
    public void onInactive() {
        setValue(Collections.emptyList());
        results.removeChangeListener(realmChangeListener);
        realm.close();
        realm = null;
    }
}

然后你可以公开一个 LiveData:

public class MyDao {
    public LiveData<List<MyObject>> findMyObjectsWithChanges() {
        return new RealmLiveData<MyObject>(new QueryDefinition<MyObject>() {
             @Override
             public RealmResults<MyObject> createResults(Realm realm) {
                 return realm.where(MyObject).findAllAsync();
             }
        });
    }
}

Lambda 表达式使它变得更好

public class MyDao {
    public LiveData<List<MyObject>> findMyObjectsWithChanges() {
        return new RealmLiveData<MyObject>((realm) -> realm.where(MyObject.class).findAllAsync());
    }
}

所以这是一个值得研究的可能性。