С последними Google I/O 2017 объявления для Android Architectural Components
, правильный путь к абстрактному Realm в Android приложений является:
1.) Жизненный цикл экземпляра Realm управляется классом ViewModel
, и он закрыт в onCleared()
метод
2.) RealmResults - это MutableLiveData<List<T>>
, поэтому вы можете создать класс RealmLiveData<T>
, который обертывает RealmResults<T>
.
Таким образом, вы можете создать модель представления, как это:
// 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;
}
}
или вы можете разделить их в сферу ViewModel и царств livedata на основе this article:
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();
}
}
В любом случае, вы 've завернутое автоматическое обновление Realm и ленивый результат, полученный в LiveData и ViewModel, отдельно от фрагментов/адаптеров:
// 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 является список прокси-объектов, мутирует на месте, и это имеет слушателей изменений.
Так что вам нужно либо обернув его как текучие с последним противодавлением, сродни
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);
}
Это шаблон, который я пытался избежать: вызов методов Realm внутри логики, не связанной с БД. Основная идея заключалась в том, чтобы абстрагировать это так, что если завтра я переключусь на другую базу данных, мне не придется переписывать такой код. –
@MarcoRomano. Тогда просто создайте класс, подобный 'DbUtils', и у вас есть метод, подобный' getYourObjectById', а затем перейдите над 'id' и получите свой объект в' return'. Разве это не сделает его абстрактным? Затем вы можете сохранить этот класс и метод и просто изменить содержание метода, если вы когда-либо переключитесь на другой db –
Вот что я в итоге сделал. Благодаря! –