2016-06-11 37 views
5

Ho un'app in cui l'utente può creare/eliminare/modificare un elenco da un DialogFragment. Prima avevo un metodo come questo nel mio DialogFragments: MainActivtity.adapter.add(String name, String location, double price);Ho usato Singleton con Realm Database corretto?

adapter è il mio oggetto adattatore per recyclerView. La classe dell'adattatore aveva i miei metodi di creazione/cancellazione/modifica per gli elementi in recyclerView. Che è stato chiamato come mostrato sopra, che è anche un modo orribile per chiamare i mehtod come capisco.

Così ho scelto di mettere tutti questi metodi CRUD in una classe Singleton e chiamare questi metodo come questo: Service.getInstance().add(...);

È questo un approccio corretto e quello che avrei potuto fare meglio?

Ecco come ho creato la classe singleton che ora contiene i miei metodi CRUD, invece di inserirli nella mia classe dell'adattatore per il recyclerView come prima.

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

Questa classe è solo utilizzato per ottenere il contesto globale/Application

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

domanda aggiornato da qui:

Ecco il nuovo approccio sulla base dei suggerimenti dai commenti: Ora everytim e Voglio fare un'operazione CRUD nel Realm Database, comincio sempre con getDefaultInstance per il mio oggetto realm e la fine di con realm.close(); questo processo viene risolto in ogni metodo CRUD.

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

configurazioni Realm è ora spostato alla mia classe di applicazione, come suggerito dal Regno.

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

Dove si chiude l'istanza reame? –

+1

Un pattern singleton è generalmente pericoloso, specialmente se si accede al singleton da thread diversi. Consulta queste due sezioni nei documenti per ulteriori informazioni su come gestire il ciclo di vita di Realm: https://realm.io/docs/java/latest/#controlling-the-lifecycle-of-realm-instances e https: // realm.io/docs/java/latest/#closing-realm-instances –

+0

@TimCastelijns nei miei metodi onDestroy. – Muddz

risposta

1

Non dovrebbe usare regno con Singleton a tutti. Come regno è orientato al filo. dovresti aprire la nuova istanza predefinita e chiuderla.

Oppure è possibile utilizzare una mappa di oggetto threadId vs realm. dove il filo è un riferimento debole.

+0

Il motivo che ho ha reso la classe Service un singleton, è così che posso chiamare il mio metodo CRUD da qualsiasi punto della mia app/codice, quindi non devo forexample per creare un metodo add(); per ogni classe che ha bisogno di questo metodo – Muddz

+0

@Muddz quindi fai una classe statica con add/remove in esso? – egfconnor

+0

@egfconnor Allright grazie per il suggerimento! – Muddz

0

Realm rappresenta un'istanza locale limitata al thread che deve essere chiusa quando il thread raggiunge la fine dell'esecuzione (o l'istanza locale non è più necessaria).

Gli oggetti recuperati dal regno sono vincolati al ciclo di vita del Regno, nel senso che sono invalidati volta ogni caso Realm è chiuso sul filetto proposta (la chiamata a getInstance() aumenta un conteggio di riferimento, e close() diminuisce).

Quindi la creazione di uno static Realm realm sarà probabilmente accessibile solo sul thread dell'interfaccia utente.

Per utilizzare Realm come Singleton (ed essere in grado di creare/recuperare esempio Realm thread-local in modo affidabile), avreste bisogno di qualcosa di simile a this:

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

In questo modo, è possibile aprire/chiudi Realm all'inizio/alla fine dell'esecuzione, ma ottieni comunque Realm senza necessariamente passarlo come argomento del metodo.

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

O

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