Corretto modo per astragare Realm in applicazioni Android

Sto provando Realm.io in un'applicazione Android, però, per rimanere sul sicuro, vorrei estrarre il livello DB in modo che, in caso di necessità, posso tornare a un DB di SQLite standard standard senza riscriversi la maggior parte dell'app.

Tuttavia, sono difficile riuscire a realmente astratta il Reame a causa della sua particolare natura:

  • Libreria di supporto multidex per Android con eclipse
  • errore aapt 138 processDebugResources
  • Imansible risolvere i pacchetti android
  • android eclipse jedisct1 / libsodium where iniziare
  • Import javax.xml.transform non può essere risolto
  • Come aggiungere le librerie Android con risorse senza utilizzare Eclipse
    • Quando legato a un regno, RealmObjects sono proxy, quindi non posso passarli come sono stati POJOs.
    • Tutte le istanze del Realm devono essere aperte e chiuse correttamente per each thread in cui vengono utilizzati.

    Ho ricorso a utilizzare la recente Realm.copyFromRealm () API anziché passare intorno a RealmObjects legato a un Realm per aggirare queste limitazioni, ma in questo modo penso che sto perdendo tutti i vantaggi di usare il regno (vero?).

    Eventuali suggerimenti?

    3 Solutions collect form web for “Corretto modo per astragare Realm in applicazioni Android”

    Cercherò di rispondere alla tua prima confusione. Non c'è veramente bisogno di passare RealmObject s attraverso intenzioni, o in altri termini non è necessario che siano parcelable o serializable

    Quello che dovresti fare è passare primary id o un altro parametro di quel particolare RealmObject attraverso l'intento, in modo da poter ricercare RealmObject nella prossima attività.

    Ad esempio, supponiamo di passare primari durante l'avvio di un'attività,

     Intent intent = new Intent(this, NextActivity.class); intent.putExtra(Constants.INTENT_EXTRA_PRIMARY_ID, id); 

    Ora dentro NextActivity otteniamo l'id dalla intenzione e semplicemente la query RealmObject , vale a dire,

     int primaryId = getIntent().getIntExtra(Constants.INTENT_EXTRA_PRIMARY_ID, -1); YourRealmObject mObject = realm.where(YourRealmObject.class).equalTo("id", primaryId).findFirst(); 

    Vedi, hai il tuo object in una nuova attività, piuttosto che preoccuparsi di passare l'object in giro.

    Non so quale particolare problema stai per entrare nell'object di apertura e chiusura dei realm. Hai provato i Transaction blocks di Realm? Non wherete contare su apertura e chiusura se lo usi.

    Spero che aiuti.

    Aggiornare

    Dato che state cercando l'astrazione,

    Basta creare una class come DbUtils e avere un metodo come getYourObjectById e quindi passare sopra id e recuperare il tuo object in cambio. Ciò lo rende astratto in un certo senso. È quindi ansible mantenere la class e il metodo e modificare il contenuto del metodo solo se si passa a un'altra soluzione di database.

    Fornire un parere diverso, visto che ho scelto di votare l'altra risposta. Vorrei prima discutere il tuo objective

    in caso di necessità, posso tornare a un DB di base standard SQLite senza riscrivere la maggior parte dell'app

    Il dominio non è equivalente a un DB di base basato su SQLite. Quello che cerchi in quel caso è qualcosa di simile a Storio . Il Realm è stato progettato in modo da poter utilizzare RealmObject come base per i tuoi templates. Se vuoi solo recuperare i dati da una tabella, il Realm non è per te.

    Ora, dopo il debacle di Parse, è apparsa la necessità di astrazione di una biblioteca di terze parti. Quindi, se questa è la tua motivazione, allora devi davvero avvolgere each singola cosa che usi dal Realm. Qualcosa come questo:

     public class Db { public class Query<M extends RealmObject> { private final RealmQuery<M> realmQuery; Query(Db db, Class<M> clazz) { this.realmQuery = RealmQuery.createQuery(db.realmInstance, clazz); } public Query<M> equalTo(String field, Integer value) { realmQuery.equalTo(field, value); return this; } public Results<M> findAll() { return new Results<>(realmQuery.findAll()); } public M findFirst() { return realmQuery.findFirst(); } } public class Results<M extends RealmObject> extends AbstractList<M> { private final RealmResults<M> results; Results(RealmResults<M> results) { this.results = results; } public void removeLast() { results.removeLast(); } @Override public M get(int i) { return results.get(i); } @Override public int size() { return results.size(); } } public interface Transaction { void execute(); abstract class Callback { public abstract void onSuccess(); public void onError(Throwable error) { } } } private Realm realmInstance; Db() { realmInstance = Realm.getDefaultInstance(); } public void executeTransaction(@NonNull Db.Transaction dbTransaction) { realmInstance.executeTransaction(realm -> dbTransaction.execute()); } public void close() { realmInstance.close(); } } 

    A questo punto, definisci solo le operazioni che utilizzi nell'applicazione sulla class Db . E, se sei come me, probabilmente non li utilizzi tutti, per cui va bene.

    È bello? No. È necessario? Dipende da ciò che vuoi raggiungere.

    Modifica : per il bonus point, implementare Db AutoCloseable :

     try(Db db = new Db()) { db.executeTransaction(() -> /*...*/); } 

    Con l'ultimo annuncio di Google I / O 2017 per Android Architectural Components , il modo giusto per astragare Realm nelle applicazioni Android è:

    1.) Il ciclo di vita di istanza Realm è gestito dalla class ViewModel e viene chiuso in metodo onCleared()

    2.) RealmResults è un MutableLiveData<List<T>> , in modo da poter creare una RealmLiveData<T> che avvolge un RealmResults<T> .

    Pertanto, è ansible creare un model di visualizzazione come questo:

     // 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; } } 

    oppure puoi separarli in un model di visione del reame e un reame vissuto in base a questo articolo :

     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 entrambi i casi, hai avvolto l'aggiornamento automatico di Realm e il set di risultati scaricati in un LiveData e ViewModel, separati dai frammenti / adattatori:

     // 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); //... } }); } } 

    Ma se non utilizzi i componenti di Architectural Android, anche quello che bisogna tenere in mente è che:

    RealmResults è un elenco di oggetti proxy che mutano in loco e ha cambiato ascoltatori.

    Quindi, ciò che ti occorre è o avvolgerlo come Flowable con la pressione SUPERIORE, simile a

     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); 

    Oppure creando l'interface MutableLiveList .

     public interface MutableLiveList<T> extends List<T> { public interface ChangeListener { void onChange(MutableLiveList<T> list); } void addChangeListener(ChangeListener listener); void removeChangeListener(ChangeListener listener); } 
    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.