2016-06-11 4 views
5

Ich habe eine App, wo der Benutzer zu einer Liste von einem DialogFragment erstellen/löschen/bearbeiten kann. Bevor ich eine Methode wie diese in meinem DialogFragments hatte: MainActivtity.adapter.add(String name, String location, double price);Habe ich Singleton mit Realm Database korrekt verwendet?

adapter ist mein Adapter-Objekt für die RecyclerView. Die Klasse für den Adapter hatte meine Methoden create/delete/edit für die Elemente in der recyclerView. Das wurde wie oben gezeigt genannt, was auch eine schreckliche Art ist, Mehtods so zu bezeichnen, wie ich es verstehe.

So wähle ich alle diese CRUD Methoden in einer Singleton-Klasse zu setzen und diese Methode wie folgen nennen: Service.getInstance().add(...);

Ist das ein richtiger Ansatz, und was könnte ich besser machen kann?

So habe ich die Singleton-Klasse erstellt, die nun meine CRUD-Methoden enthält, anstatt sie wie bisher in meine Adapterklasse für den RecyclerView einzufügen. ist

Hier den neuen Ansatz auf Vorschläge basieren:

public class Service { 

private static Realm realm; 
private static Service service = new Service(); 

private Service() { 
    realm = Realm.getInstance(App.getAppContex()); 
} 

public static Service getInstance(){ 

    if(service == null){ 
     service = new Service(); 
    } 
    return service; 
} 



    public void add(String name, String location, double price) { 


    ShopListItem shopListItem = new ShopListItem(); 

    shopListItem.setName(name); 
    shopListItem.setLocation(location); 
    shopListItem.setPrice(price); 
    shopListItem.setTimestamp(System.currentTimeMillis()); 
    shopListItem.setIsBought(0); 

    realm.beginTransaction(); 
    realm.copyToRealm(shopListItem); 
    realm.commitTransaction(); 
} 


public void removeItem(int position, List<ShopListItem> shopListItems) { 

    realm.beginTransaction(); 
    shopListItems.remove(position); 
    realm.commitTransaction(); 
} 

Diese Klasse wird für das Erhalten der globalen/Anwendungskontext

public class App extends Application { 


public static Application sApplication; 

public static Application getsApplication(){ 
    return sApplication; 
} 

public static Context getAppContex(){ 

    return getsApplication(); 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 
    sApplication = this; 
} 
} 

Frage aktualisiert von hier nur verwendet von den Kommentaren: Jetzt Evertimtim e Ich möchte eine CRUD-Operation in der Realm-Datenbank machen, ich beginne immer mit der getDefaultInstance für mein Realm-Objekt und beende mit realm.close(); Dieser Prozess wird in jeder CRUD-Methode angepasst.

public class Service { 

private Realm realm; 
private static Service service = new Service(); 

private Service() { 


} 

public static Service getInstance(){ 

    if(service == null){ 
     service = new Service(); 
    } 
    return service; 
} 

public void removeItem(int position, List<ShopListItem> shopListItems) { 
    //new: realm = Realm.getDefaultInstance(); 

    realm = Realm.getDefaultInstance(); 
    realm.beginTransaction(); 
    shopListItems.remove(position); 
    realm.commitTransaction(); 
    realm.close(); 
    //new: realm.close(); 
} 

Realm Konfigurationen wird nun auf meine Anwendungsklasse bewegt, wie durch Realm vorgeschlagen.

public class App extends Application { 


public static Application sApplication; 

public static Application getsApplication(){ 
    return sApplication; 
} 

public static Context getAppContex(){ 

    return getsApplication(); 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 
    sApplication = this; 
final RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(App.getAppContex()).build(); 
    realm.setDefaultConfiguration(realmConfiguration); 
} 
} 
+0

Wo Sie das Reich Instanz schließen Sie? –

+1

Ein Singleton-Muster ist im Allgemeinen gefährlich, besonders wenn Sie auf das Singleton von verschiedenen Threads zugreifen. Weitere Informationen zum Umgang mit dem Realm-Lebenszyklus finden Sie in den beiden folgenden Abschnitten in den Dokumenten: https://realm.io/docs/java/latest/#controlling-the-lifecycle-of-realm-instances und https: // realm.io/docs/java/latest/#closing-realm-instances –

+0

@TimCastelijns in meinen OnDestroy-Methoden. – Muddz

Antwort

1

Sie sollten Realm überhaupt nicht mit Singleton verwenden. Als Realm ist Thread orientiert. Sie sollten die neue Standardinstanz öffnen und sie schließen.

Oder Sie können eine Karte von threadId vs Realm-Objekt verwenden. Wo Thread ist schwache Referenz.

+0

Der Grund, warum ich habe machte die Service-Klasse zu einem Singleton, damit ich meine CRUD-Methode von überall in meiner App/Code aufrufen kann. Also muss ich nicht extra eine add(); -Methode für jede Klasse erstellen, die diese Methode benötigt – Muddz

+0

@Muddz also mach eine statische Klasse mit add/remove drin? – egfconnor

+0

@egfconnor Alles Gute, danke für den Tipp! – Muddz

0

Realm stellt eine lokal begrenzte lokale Instanz dar, die geschlossen werden muss, wenn der Thread das Ende der Ausführung erreicht (oder die lokale Instanz nicht mehr benötigt wird).

Alle aus dem Realm abgerufenen Objekte sind an den Lebenszyklus des Realms gebunden, dh sie werden ungültig, sobald jede Realm-Instanz für den angegebenen Thread geschlossen wird (der Aufruf an getInstance() erhöht einen Referenzzähler und close() verringert ihn).

Das Erstellen eines static Realm realm wird höchstwahrscheinlich nur im UI-Thread verfügbar sein.

Um Realm als Singleton zu verwenden (und der Lage sein, lokale Thread-Realm-Instanz in zuverlässiger Weise erstellen/abrufen), können Sie so etwas wie this bräuchten:

@Singleton 
public class RealmManager { 
    private final ThreadLocal<Realm> localRealms = new ThreadLocal<>(); 

    @Inject 
    RealmManager() { 
    } 

    /** 
    * Opens a reference-counted local Realm instance. 
    * 
    * @return the open Realm instance 
    */ 
    public Realm openLocalInstance() { 
     checkDefaultConfiguration(); 
     Realm realm = Realm.getDefaultInstance(); 
     if(localRealms.get() == null) { 
      localRealms.set(realm); 
     } 
     return realm; 
    } 

    /** 
    * Returns the local Realm instance without adding to the reference count. 
    * 
    * @return the local Realm instance 
    * @throws IllegalStateException when no Realm is open 
    */ 
    public Realm getLocalInstance() { 
     Realm realm = localRealms.get(); 
     if(realm == null) { 
      throw new IllegalStateException(
        "No open Realms were found on this thread."); 
     } 
     return realm; 
    } 

    /** 
    * Closes local Realm instance, decrementing the reference count. 
    * 
    * @throws IllegalStateException if there is no open Realm. 
    */ 
    public void closeLocalInstance() { 
     checkDefaultConfiguration(); 
     Realm realm = localRealms.get(); 
     if(realm == null) { 
      throw new IllegalStateException(
        "Cannot close a Realm that is not open."); 
     } 
     realm.close(); 
     // noinspection ConstantConditions 
     if(Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) { 
      localRealms.set(null); 
     } 
    } 

    private void checkDefaultConfiguration() { 
     if(Realm.getDefaultConfiguration() == null) { 
      throw new IllegalStateException("No default configuration is set."); 
     } 
    } 
} 

Auf diese Weise können Sie öffnen/close Realm am Anfang/Ende der Ausführung, aber erhalte trotzdem Realm, ohne es unbedingt als Methodenargument zu übergeben.

private void doSomething() { 
    Realm realm = realmManager.getLocalInstance(); 

Oder

realmManager.openLocalInstance(); 
    // .. do whatever 
    realmManager.closeLocalInstance(); 
Verwandte Themen