2017-09-21 5 views
1

J'utilise Dagger 2 pour fournir une instance de domaine singleton pour l'application entière (tous les objets d'accès aux données utilisent un seul domaine). Cependant, pour autant que je sache, Royaume peut avoir plusieurs instances en utilisant Realm.getInstance() et nous devons fermer chaque instance lorsque nous en avons terminé avec comme présenté par le royaume docs:Dague 2 - Dois-je utiliser une instance de royaume singleton?

/** 
    * Closes the Realm instance and all its resources. 
    * <p> 
    * It's important to always remember to close Realm instances when you're done with it in order not to leak memory, 
    * file descriptors or grow the size of Realm file out of measure. 
    * 
    * @throws IllegalStateException if attempting to close from another thread. 
    */ 
    @Override 
    public void close() { 
     if (this.threadId != Thread.currentThread().getId()) { 
      throw new IllegalStateException(INCORRECT_THREAD_CLOSE_MESSAGE); 
     } 

     if (realmCache != null) { 
      realmCache.release(this); 
     } else { 
      doClose(); 
     } 
    } 

Ma question est la suivante: dois-je utiliser une instance de domaine singleton comme je l'ai fait, ou créer une instance de domaine pour chaque activité/fragment et la fermer en utilisant realm.close() à onDestroy()?

Répondre

2

Les RealmObjects gérés (qui sont chargés par leur accès) ne sont accessibles que s'il existe au moins 1 instance de Realm sur ce thread, mais la fermeture de l'instance Realm sur un thread d'arrière-plan non-looper est un problème très grave.

Si vous fournissez un Realm à partir du module Dagger de thread-singleton local, cette instance de Realm ne sera accessible que sur le thread sur lequel elle a été créée. Et provoquera un accident accédé de n'importe où ailleurs.

Une possibilité serait de fournir une classe singleton de votre propre qui peut ouvrir les instances de royaume, comme this:

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

    @Inject 
    public RealmManager() { 
    } 

    /** 
    * Opens a reference-counted local Realm instance. 
    * 
    * @return the open Realm instance 
    */ 
    public Realm openLocalInstance() { 
     checkDefaultConfiguration(); 
     Realm realm = Realm.getDefaultInstance(); // <-- maybe this should be configurable 
     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."); 
     } 
    } 
} 

Mais même alors, you'd need to manage the local instances for the given threads where you need them.

public class MainActivity 
     extends AppCompatActivity { 
    RealmManager realmManager; 

    ... 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     realmManager = Injector.get().realmManager(); 
     realmManager.openLocalInstance(); 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     ButterKnife.bind(this); 
     ... 
    } 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     realmManager.closeLocalInstance(); 
    } 
+0

beeeeeeeeeeeep. – EpicPandaForce

3

Une instance singleton vous cause probablement des problèmes. Vous devriez en créer un pour chaque activité/fragment à la place.

+0

Tout exemple de problème peut-il être? – Pelocho

+2

Vous allez probablement rencontrer une exception 'IllegalStateException' car vous accédez à l'instance Realm à partir du mauvais thread ou vous l'avez fermé par accident. En tout cas, vous le découvrirez très vite. –

+0

C'était la réponse à laquelle je m'attendais. Déclarer simplement que cela «va probablement vous causer des problèmes» est un peu ... résumé – Pelocho