Jak používat Realm pro Android jako šampion a jak zjistit, zda se vám nedaří

Realm používám dlouhou dobu (od v0.81.1) a měl bych si uvědomit, že nejsem spojen s Realm. Ale od té doby sleduji spoustu zlomových změn a viděl jsem pár příspěvků o tom, jak používat Realm… a většina z nich se nějakým způsobem mýlila. Přeplněné, náchylné k chybám nebo prostě špatně.

Nejnovější verze v tuto chvíli je v5.9.0, nejnovější verzi si můžete prohlédnout na svých webových stránkách. Pravděpodobně byste měli aktualizovat, pokud jste pozadu.

Každopádně vám zde řeknu, jak zjistit, zda je příklad, který čtete, špatný, nebo pokud máte něco v pořádku. Nejprve však velmi krátké úvod do Realmu.

Co je říše?

Realm je databázový systém. Je to trochu jako SQLite, kromě toho, že to vůbec nemá nic společného s SQLite. Definujete třídy, tyto třídy definují vaše schéma a Realm ukládá instance této třídy jako objekty. Není to databáze SQL, je to databáze NoSQL. Je to poměrně snadné použití a má také některé docela skvělé funkce - ale podrobněji se o tom podrobněji podívám v článku.

Každopádně zpět na trať:

Typické chyby, které lidé zřejmě dělají neustále

  • pomocí realm.beginTransaction () a realm.commitTransaction () místo realm.executeTransaction (Realm.Transaction)

Problém je v tom, že executeTransaction () automaticky zpracovává volání realm.cancelTransaction () v případě vyvolání výjimky, zatímco jiná alternativa obvykle zanedbává try-catch.

Ano, máte zavolat zrušení u transakcí, u nichž se nakonec nedopustí spáchání.

Například v podprocesech na pozadí:

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • otevírání instancí Realmu pomocí Realm.getDefaultInstance (), které se nikdy nikam nezavírají

Problém je v tom, že v podprocesech na pozadí má otevřená instance Realm, kterou nezavřete, i když je provedení podprocesu u konce, velmi nákladné a může způsobit podivné chyby. Proto se doporučuje zavřít říši na pozadí podprocesu, když je provádění provedeno v konečném bloku. To zahrnuje IntentServices.

Měli byste také zvážit uzavření instance Realm ve vašem podprocesu uživatelského rozhraní, když již nemáte Aktivity, takže můžete ukončit nekomprimovanou Realm při ukončení. Nemůžete to udělat, pokud máte otevřené případy. (Osobně mám jednu globální instanci Realm pro vlákno uživatelského rozhraní a zavřete ji, když neexistují žádné otevřené aktivity).

Zde je pravidlo: Pokud uvidíte kód, jako je Realm.getDefaultInstance (). Kde (...), dříve nebo později se zlomí.

(Také tip: měli byste otevřít první instanci Realmu v podprocesu uživatelského rozhraní až po vytvoření první aktivity, abyste byli v bezpečí před context.getFilesDir () == null).

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • provádění mnoha transakcí (například každý prvek je přidán do nové transakce, ve smyčce for-loop) na nealooperujících neautomatizujících podprocesech na pozadí

V určitém okamžiku to způsobí potíže. Minimalizujte počet transakcí pro dané vlákno pozadí.

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • zneužití realmResults.asObservable () a nepochopení podpory Rm Realm obecně

Většina otázek souvisejících s Rx / Realm o přetečení zásobníku má tendenci být příliš kryptická, protože dochází k zásadnímu nedorozumění ohledně toho, co má podpora Realm Rx dělat.

Smyslem realmResults.asObservable () je vidět celý výsledek jako pozorovatelný bez nutnosti manuálního přidávání posluchačů změn a být neustále aktuální (a přijímat oznámení v případě změny tabulky) na podprocesu UI.

Pokud flatMap RealmResults, jste nakonec nakonec zmateni. Chtěl jsem najít případ použití, ve kterém je to vyžadováno, a ještě jsem ho nenašel. Používání switchMap však dává smysl.

V případě, že vás to zajímá, měli byste otevřít a zavřít instanci Realm pro vaše pozadí vlákna, i když ji použijete s Rx.

Pokud opravdu potřebujete RealmResults na vláknu pozadí jako Observable (nikdy se mi nikdy nestalo), použijte Observable.just (realm.where (…) .find * ()) (not async) namísto asObservable ().

(Poznámka: Před Realm 2.0.3+ byste měli zvážit použití vlastního RealmObservableFactory, protože byl nalezen únik paměti.)

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • pokus o stránkování RealmResults nebo „omezit počet výsledků v něm“ bez platného důvodu

Viděl jsem lidi, kteří se pokoušejí zobrazit stránky RealmResults, nebo „jak mohu udělat dotaz na limit“. První položená otázka zní, proč se to snažíte.

Většinou proto, že chcete omezit RealmResults, jednoduše jej nemusíte indexovat nad svůj libovolný práh.

esseChcete-li to objasnit: RealmResults NEBUDE obsahovat žádné prvky. Obsahuje prostředky k vyhodnocení výsledků dotazu. Prvek je získán z Realmu pouze tehdy, když voláte realmResults.get (i), a najednou se vrací pouze jediný element. Je to jako kurzor, s výjimkou seznamu. Proto „omezení“ a „stránkování“ to nedává smysl. Pokud to opravdu potřebujete, omezte svůj index.

- - - - - - - - - - - - - - - - - - - - - - - - - -

Pokud vidíte findAll (). Sort (), mělo by to být typicky sort (). FindAll (). Před Realm-Java 5.0.0 to bývalo findAllSorted (), takže to hledejte.

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • Nepoužívejte @Index anotace v polích, které používáte v dotazu, i když byste měli

Díky tomu jsou vaše dotazy jako 4x rychlejší, pokud ne více. Pokud použijete pole v dotazu, měli byste vždy použít @Index.

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • Otevření instance Realm na podprocesu na pozadí, získání RealmResults, THEN otevření transakce a manipulace s výsledky na vnější straně transakce

Když otevřete transakci, píšete přímo do nejnovější verze Realmu. Což znamená, že vaše RealmResults by měly být získány VNITŘNÍ transakci a NE mimo transakci; takže vždy uvidíte nejnovější verzi.

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • Nepoužíváte RealmRecyclerViewAdapter a RecyclerView, i když je to už nějakou dobu venku

Rovněž stojí za zmínku, že jejich adaptér (verze 3.0.0) spravuje přidávání a odebírání posluchače změn, který volá správný adaptér adaptéru. prvky na obrazovce a funguje to a automaticky se aktualizuje, když se něco stane.

ListViews a AsyncTasks mě cítí bolest. : /

- - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - -

Jednalo se většinou o běžné chyby, ale o co vlastně jde?

Realm řeší několik problémů, které by jinak vyžadovaly spoustu instalatérských prací, aby se zvládly, což je to, co je v první řadě docela v pohodě.

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • Vyhodnocení dotazu s nulovou kopií

Což je to, co jsem řekl dříve o RealmResults neobsahujícím žádné prvky. Třídy proxy se vytvoří pouze při volání .get (i). Seznam, který získáte, je pouze ozdobným kurzorem do základní databáze. Vyhodnocení samotných RealmResults je poměrně levné a umožňuje snadný přístup ke všem datům, která splňují vaše podmínky, bez kopírování celé sady dat do paměti.

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • Povolení zápisů z více podprocesů (pouze jedna transakce najednou) a automatické aktualizace v podprocesu UI k zobrazení nejnovější verze dat

Vaše operace na pozadí stáhla novou šarži koček na vlákno pozadí. Nyní musíte nějakým způsobem ukázat tyto nové kočky na starých kočkách ve vašem RecyclerView. Předpokládejme, že nenávidíte AsyncTasks, protože se vám líbí otáčení obrazovky.

Nově vložené prvky můžete poslat přes sběrnici událostí, připojit je do svého seznamu a poté zavolat adapter.notifyItemRangeInserted (...), ale nebylo by skvělé, kdybyste jen zapsali data na jednom místě a data byla všude jinde aktuální bez manuálního instalatérství?

Ano, pokud použijete RealmResults vrácený vaším dotazem a hodíte jej do RealmRecyclerViewAdapter (který mimochodem příliš nekouří magii na pozadí), jakýkoli zápis, který uděláte na libovolném vlákně, AUTOMATICKY aktualizuje vaši výsledkovou sadu, vždy zobrazuje nejnovější data. Super, co?

- - - - - - - - - - - - - - - - - - - - - - - - - -

  • Poslech asynchronně získaných výsledků dotazu bez velkého úsilí

Pokud nepoužíváte RealmRecyclerViewAdapter, můžete stále poslouchat všechny změny provedené z jakýchkoli vláken pomocí RealmChangeListener přidaného do vašich RealmResults.

soukromá říše;
soukromé kočky RealmResults ;
soukromý RealmChangeListener <...> realmChangeListener = kočky -> {
    adapter.setData (kočky);
};
@Override
protected void onCreate (Bundle savedInstanceState) {
    super.onCreate (uloženéInstanceState);
    realm = Realm.getDefaultInstance ();
    cats = realm.where (Cat.class) .findAllAsync ();
    cats.addChangeListener (realmChangeListener);
}
@Override
chráněné neplatné naDestroy () {
    super.onDestroy ();
    cats.removeAllChangeListeners ();
    realm.close ();
}

- - - - - - - - - - - - - - - - - - - - - - - - - -

S ohledem na to, jak by se měla říše používat?

  • Nepoužívejte beginTransaction () a commitTransaction () ručně. Použijte executeTransaction () (nebo executeTransactionAsync () v podprocesu UI, pokud je to potřeba).
  • Pomocí metody RealmRecyclerViewAdapter s metodou findAllSortedAsync () zcela odložte dotaz z podprocesu uživatelského rozhraní a automaticky zobrazte všechny nové prvky přidělené z podprocesů na pozadí (adaptér Realm to za vás zpracovává pomocí RealmChangeListener)
  • Nevyžaduje se žádné ruční kopírování ani synchronizace, stačí definovat dotaz a jak spojit držitele pohledu s objektem Realm a získáte řešení pro využití paměti s automatickou synchronizací.

Pokud se přesto nevzdáváte kopírování dat v paměti, můžete zkusit Monarchii.

- - - - - - - - - - - - - - - - - - - - - - - - - -

Doufejme, že vám to pomohlo:

  • trochu porozumět tomu, co je Realm, k čemu Realm patří a jak s ním pracovat
  • jak identifikovat špatné příspěvky, jako je tento (nadměrná správa instance Realm, synchronní transakce v podprocesu uživatelského rozhraní, místo spuštění / potvrzení místo spuštění, instance Realmu, které NIKDY nejsou uzavřeny, což vám říká, abyste přidali počáteční data pomocí migrace namísto initialData (Realm) . Transakce) pomocí metod, které již neexistují od 0.89.0… takové věci).

Přepracoval jsem příklad knihy zobrazený na tomto příspěvku výše v tomto úložišti Github.

Jednoduchý příklad, který stahuje externí data, najdete v tomto úložišti Github.

(Mimochodem, s novou funkcí tleskání média, pokud se vám článek líbil, můžete skutečně stisknout tlačítko „tleskat“ a vyjádřit, jak se vám to líbilo!)