With the latest Google I / O 2017 announcement for Android Architectural Components , the correct way to abstract Realm in Android applications:
1.) The life cycle of a Realm instance is controlled by the ViewModel class, and it is closed in the onCleared() method
2.) RealmResults is a MutableLiveData<List<T>> , so you can create a RealmLiveData<T> class that wraps RealmResults<T> .
Therefore, you can create a view model as follows:
or you can split them into realm viewmodel and realm liveata based on in 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(); } }
In any case, you turned off the automatic update of Realm and the lazy loaded result in LiveData and ViewModel, separately from fragments / adapters:
// 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); //... } }); } }
But if you are not using the architectural components of Android, even then what you need to remember is this:
RealmResults is a list of proxy objects that mutate in place, and it has change listeners.
So you need to either wrap it as Flowable with the LAST backpressure, akin to
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);
Or create your own MutableLiveList interface.
public interface MutableLiveList<T> extends List<T> { public interface ChangeListener { void onChange(MutableLiveList<T> list); } void addChangeListener(ChangeListener listener); void removeChangeListener(ChangeListener listener); }