gpt4 book ai didi

android - 在 Android 应用程序中抽象 Realm 的正确方法

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:54:00 25 4
gpt4 key购买 nike

我正在 Android 应用程序中试用 Realm.io,不过,为了安全起见,我想抽象 DB 层,以便在需要时可以切换回基于 SQLite 的标准无需重写大部分应用程序的数据库。

然而,由于 Realm 的特殊性质,我发现很难正确抽象它:

  • 当绑定(bind)到一个 Realm 时,RealmObjects 是代理,所以我不能像 POJO 一样传递它们。
  • 所有 Realm 实例都需要在使用它们的每个线程中正确打开和关闭。

我已经使用最近的 Realm.copyFromRealm() API 而不是传递与 Realm 绑定(bind)的 RealmObjects 来绕过这些限制,但我认为这样我就失去了使用 realm 的所有好处(是吗? ).

有什么建议吗?

最佳答案

随着最新的 Google I/O 2017 公告 Android Architectural Components ,在 Android 应用程序中抽象 Realm 的正确方法是:

1.) Realm 实例生命周期由 ViewModel 管理类,并在 onCleared() 中关闭方法

2.) RealmResults 是一个 MutableLiveData<List<T>> , 所以你可以创建一个 RealmLiveData<T>包装 RealmResults<T> 的类.

因此,您可以像这样创建一个 View 模型:

// based on  https://github.com/googlesamples/android-architecture-components/blob/178fe541643adb122d2a8925cf61a21950a4611c/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.java
public class ProductListViewModel {
private final MutableLiveData<List<ProductEntity>> observableProducts = new MutableLiveData<>();

Realm realm;
RealmResults<ProductEntity> results;
RealmChangeListener<RealmResults<ProductEntity>> realmChangeListener = (results) -> {
if(results.isLoaded() && results.isValid()) { // you probably don't need this, just making sure.
observableProducts.setValue(results);
}
};

public ProductListViewModel() {
realm = Realm.getDefaultInstance();
results = realm.where(ProductEntity.class).findAllSortedAsync("id");
// could use a Realm DAO class here
results.addChangeListener(realmChangeListener);

observableProducts.setValue(null); // if using async query API, the change listener will set the loaded results.
}

public LiveData<List<ProductEntity>> getProducts() {
return observableProducts;
}

@Override
protected void onCleared() {
results.removeChangeListener(realmChangeListener);
realm.close();
realm = null;
}
}

或者您可以根据this article将它们分成 Realm View 模型和 Realm 实时数据。 :

public class LiveRealmData<T extends RealmModel> extends LiveData<RealmResults<T>> {

private RealmResults<T> results;
private final RealmChangeListener<RealmResults<T>> listener =
new RealmChangeListener<RealmResults<T>>() {
@Override
public void onChange(RealmResults<T> results) { setValue(results);}
};

public LiveRealmData(RealmResults<T> realmResults) {
results = realmResults;
}

@Override
protected void onActive() {
results.addChangeListener(listener);
}

@Override
protected void onInactive() {
results.removeChangeListener(listener);
}
}

public class CustomResultViewModel extends ViewModel {

private Realm mDb;
private LiveData<String> mLoansResult;

public CustomResultViewModel() {
mDb = Realm.getDefaultInstance();
mLoansResult = RealmUtils.loanDao(mDb).getAll();
}

public LiveData<String> getLoansResult() {
return mLoansResult;
}

@Override
protected void onCleared() {
mDb.close();
super.onCleared();
}
}

无论哪种方式,您都将 Realm 的自动更新和延迟加载结果集包装到 LiveData 和 ViewModel 中,与 fragment/适配器分开:

// based on https://github.com/googlesamples/android-architecture-components/blob/178fe541643adb122d2a8925cf61a21950a4611c/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.java
public class ProductListFragment extends LifecycleFragment {
private ProductAdapter productAdapter;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
//...
productAdapter = new ProductAdapter(mProductClickCallback);
//...
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ProductListViewModel viewModel =
ViewModelProviders.of(this).get(ProductListViewModel.class); // <-- !

subscribeUi(viewModel);
}

private void subscribeUi(ProductListViewModel viewModel) {
// Update the list when the data changes
viewModel.getProducts().observe(this, (myProducts) -> {
if (myProducts == null) {
// ...
} else {
productAdapter.setProductList(myProducts);
//...
}
});
}
}

但是,如果您使用 Android 架构组件,即便如此,您也需要牢记:

RealmResults is a list of proxy objects that mutates in place, and it has change listeners.

所以你需要的是将它包装为具有最新背压的 Flowable,类似于

private io.reactivex.Flowable<RealmResults<T>> realmResults() {
return io.reactivex.Flowable.create(new FlowableOnSubscribe<RealmResults<T>>() {
@Override
public void subscribe(FlowableEmitter<RealmResults<T>> emitter)
throws Exception {
Realm observableRealm = Realm.getDefaultInstance();
RealmResults<T> results = realm.where(clazz)./*...*/.findAllSortedAsync("field", Sort.ASCENDING);
final RealmChangeListener<RealmResults<T>> listener = _results -> {
if(!emitter.isDisposed()) {
emitter.onNext(_results);
}
};
emitter.setDisposable(Disposables.fromRunnable(() -> {
observableRealm.removeChangeListener(listener);
observableRealm.close();
}));
observableRealm.addChangeListener(listener);
emitter.onNext(observableRealm);
}
}, BackpressureStrategy.LATEST).subscribeOn(scheduler).unsubscribeOn(scheduler);

或创建您自己的 MutableLiveList界面。

public interface MutableLiveList<T> extends List<T> { 
public interface ChangeListener {
void onChange(MutableLiveList<T> list);
}

void addChangeListener(ChangeListener listener);
void removeChangeListener(ChangeListener listener);
}

关于android - 在 Android 应用程序中抽象 Realm 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34473611/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com