2017-06-06 2 views
0

Ich habe eine App, die MVP-Muster mit einem Loader, um das Presenter-Objekt auf Ansicht Erholung (es gibt einen Artikel über diese here). Ich bin neu in Dagger 2 und versuche, es zusammen mit dem aktuellen Code zu implementieren.Dolch 2 mit MVP, vermeiden Sie das Erstellen zusätzlicher Präsentator Objekt auf Ansicht Erholung

Ich habe es geschafft, es funktioniert, aber jetzt ist mein Presenter zweimal erstellt. Zuerst wurde es unter Verwendung einer Factory-Klasse erstellt, die in onCreateLoader initialisiert wurde, aber dann, als ich die Dagger 2-Implementierung hinzufügte, hatte ich zwei Objekte erstellt (in der Factory-Klasse und beim Injizieren).

Jetzt vermeide ich es, einen neuen Moderator in onCreateLoader zu erstellen und übergibt stattdessen den injizierten Moderator. Das Problem besteht in der Wiedereröffnung der Ansicht: Jedes Mal, wenn die Ansicht zerstört und neu erstellt wird, wird ein neuer Präsentator in OnCreate/OnCreateView injiziert. Dies ist das Szenario:

  1. Ein neuer Moderator injiziert wird:

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
        ... 
        getControllerComponent().inject(this); 
        ... 
    } 
    
  2. Loader Initialisierung wird onCreateLoader aufgerufen, wenn die Loader nicht vorhanden ist. Beachten Sie, dass wir den Moderator, die injiziert wurde passieren:

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
        super.onActivityCreated(savedInstanceState); 
        getLoaderManager().initLoader(PRESENTER_LOADER_ID, null, this); 
    } 
    
    @Override 
    public Loader<MyPresenter> onCreateLoader(int id, Bundle args) { 
        switch (id) { 
         case PRESENTER_LOADER_ID: 
          return new PresenterLoader<>(getContext(), presenter); 
          //return new PresenterLoader<>(getContext(), new MyPresenterFactory()); 
        } 
    
        return null; 
    } 
    
  3. Zuordnung der Moderator vom Loader erhalten. Wenn es gerade erstellt wurde, weisen wir dasselbe Objekt zu, das bereits zugewiesen wurde, sodass nichts passiert. Aber wenn die Ansicht neu erstellt wurde, hat Dagger 2 einen neuen Moderator eingespritzt und hier werfen wir den neuen Moderator weg und ersetzen ihn durch den alten Moderator von Loader.

    @Override 
    public void onLoadFinished(Loader<MyPresenter> loader, MyPresenter data) { 
        this.presenter = data; 
    } 
    

    Ich möchte die Presenter-Instanz verwalten, damit ± was ich will; Mein Problem ist das Erstellen eines redundanten Presenterobjekts in jeder Ansichtsreproduktion. Erstens ist es unnötig, und außerdem enthält die Ansicht einen Verweis auf einen anderen Präsentator, bis die Last beendet ist. Offensichtlich benutze ich den Moderator während dieser Zeit nicht (nach der Injektion und bevor die Ladung fertig ist), aber ich mag sie definitiv nicht und habe Angst, dass dieser neue Moderator irrtümlicherweise in der Zukunft verwendet wird.

Dagger 2 Experten ist es eine Möglichkeit, den Presenter zum ersten Mal zu erstellen (vor Loader erstellt wird), aber es auf Sicht Erholung zu vermeiden? Danke vielmals!

+0

Könnten Sie die Dolch-Komponentendefinition und Module teilen, von denen es abhängt? –

Antwort

6

Zunächst möchte ich nur erwähnen, dass wenn Sie Ihren Moderator injizieren, sollten Sie es nicht später wieder von Ihrem Lader zuweisen.

Verwenden Sie entweder die Injektion, um ein Objekt bereitzustellen, oder stellen Sie es selbst bereit. Wenn Sie beides tun, sind Sie nur gefährdet, Bugs einzuführen.


ist es eine Möglichkeit, den Presenter zum ersten Mal zu erstellen (vor Loader erstellt wird), aber es auf Sicht Erholung zu vermeiden?

tl; dr Sie benötigen einen Rahmen für Ihren Moderator, der die Lebensdauer der Komponente widerspiegelt, die Konfigurationsänderungen überleben könnten. Dieser Bereich darf keinen Bezug zu den Aktivitäten Context enthalten.

Komponenten folgen einem gewissen Lebenszyklus. Sie haben normalerweise @Singleton annotierte Komponente, die Sie innerhalb Ihrer Application und einige @PerActivity oder ähnlichem Umfang Komponenten, die Sie erstellen, per Activity, die neu erstellt werden, wenn eine Aktivität Konfigurationsänderungen durchläuft, da diese Abhängigkeiten oft verweisen auf den Aktivitätskontext und sollte mit der Aktivität leben und sterben.

Das Hauptproblem, dem Sie hier gegenüberstehen, ist ein Problem mit der Bereichsdefinition.

Wenn Ihr Präsentator nicht gescannt ist, erstellen Sie jedes Mal, wenn Sie einen neuen Präsentator anfordern, einen neuen Moderator, der versehentlich zu Fehlern führt, sobald Sie ihn an anderer Stelle injizieren. Üblicherweise werden die Moderatoren innerhalb der Aktivität gehalten und oft von einem Bereich umspannt.


Wenn Ihr Moderator Teil des @PerActivity Umfangs ist es sollte (wie alle anderen @PerActivity Abhängigkeiten) zusammen mit all den anderen Abhängigkeiten neu erstellt werden. Wenn Sie den Präsentator beibehalten, aber alle anderen Objekte neu erstellen, verweist der alte Präsentator weiterhin auf die alten Abhängigkeiten und erstellt Speicherlecks. Scoped Objekte sollten nur in ihrem eigenen Umfang existieren.

Objekte im selben Umfang kann ein scoped Objekt am Leben führen auch versehentlich wird Lecks Speicher Fehler, außerhalb des Anwendungsbereichs einander und somit Referenz zu halten usw.

Sie wollen also nicht halten Diese Presenter in Ihrem Loader entweder.


Wenn auf der anderen Seite Sie Nein sagen, dass Moderator ist eine Stufe höher in der Hierarchie, Teil @PerScreen, wo ich immer mehr Wohnobjekte dann müssen Sie einen Weg finden, um tatsächlich diese @PerScreen zu halten Komponente lebendig, während Ihre @PerActivity Komponente zusammen mit der Aktivität neu erstellt wird.

Angenommen, die folgenden Bereichshierarchie:

`X > Y` read X is subcomponent of Y 
@Singleton > @PerScreen > @PerActivity 

@Singleton: Application wide 
@PerScreen: Multiple activty lifecycles, keep alive during config changes 
@PerActivity: Maybe Context dependent, recreate with every activity 

Wenn eine Konfigurationsänderung Sie jetzt tritt alle der @PerActivity Objekte verwerfen und erstellen Sie sie, während Sie den Verweis auf Ihre @PerScreen diejenigen zu halten.

Vielleicht haben Sie bemerkt, wie ich über die @PerScreen Komponente zu halten Gespräch halten, nicht den Moderator zu halten, und das ist der wichtige Teil hier:

Auf der @PerScreen Komponente scoped, ruft

myPerScreenComponent.getMyPresenter() 

wird immer den gleichen@PerScreen Scoped Presenter zurückgeben. Jetzt

wenn Ihr @PerActivty scoped Komponente ist eine Subkomponente von MyPerScreenComponent, Ihre Aktivität Injektion geben Ihnen immer die gleiche @PerScreen scoped Moderator, die Orientierungsänderungen überleben.

Um Speicherlecks, kein Objekt von Ihrem @PerScreen Umfang verweisen kann die Aktivität, und der Moderator sollte nur halten zu verhindern, dass ein WeakReference auf seiner Ansicht (oder Sie haben verdammt sicher zu machen, um die Ansicht zu null auf zerstören zu setzen).

Das ist, was Bereiche sind und das ist, wie Sie avoid auf Sicht Erholung zusätzlichen Moderator Objekt erstellen.

Anstatt also Ihren Presenter in Ihrem Loader zu behalten, sollten Sie versuchen, die Komponente in Ihrem Loader zu behalten, um unnötige Wiederherstellung Ihrer Objekte zu vermeiden.

All dies wird wahrscheinlich viel mehr Komplexität einführen, da Sie jetzt 2 Bereiche pro Aktivität und mehr Callbacks haben.

Ich habe auch andere Ansätze gesehen, bei denen Sie Ihre Vortragenden als Singletons in Ihrer Anwendung behalten, aber dies führt zu denselben Problemen, bei denen Sie sicherstellen müssen, dass Sie keine Referenzen auf Ihre Aktivität behalten.

Persönlich würde ich nur die Präsentatoren neu erstellen und den Status wiederherstellen, aber wenn Sie mit Ihrem Ansatz gehen, sollten Sie sicherstellen, dass Sie ein solides Verständnis von Bereichen und Abhängigkeiten haben.