2017-02-24 4 views
0

Ich habe dagger2-Abhängigkeiten in meiner App so eingerichtet, wie ich es verstehe und durch die vielen Beispiele. Was ich nicht gefunden habe, ist der richtige Weg, alle Abhängigkeiten zu nutzen, sobald sie injiziert sind.Dagger2 Verwenden eines vollständigen Abhängigkeitsgraphen

Jedes der Singletons im Modul ist abhängig von der Ausgabe des Singletons davor. Wie wird das gesamte Abhängigkeitsdiagramm verwendet, ohne nacheinander alle Singletons aufzurufen, um die erforderlichen Eingaben zu erhalten?

Angesichts der folgenden:

AppComponent

@Singleton 
@Component(modules = { 
     DownloaderModule.class 
}) 
public interface AppComponent { 
    void inject(MyGameActivity activity); 
} 

DownloaderModule

@Module 
public class DownloaderModule { 

    public static final String NETWORK_CACHE = "game_cache"; 

    private static final int GLOBAL_TIMEOUT = 30; // seconds 

    public DownloaderModule(@NonNull String endpoint) { 
     this(HttpUrl.parse(endpoint)); 
    } 

    @Provides @NonNull @Singleton 
    public HttpUrl getEndpoint() { 
     return this.endpoint; 
    } 

    @Provides @NonNull @Singleton @Named(NETWORK_CACHE) 
    public File getCacheDirectory(@NonNull Context context) { 
     return context.getDir(NETWORK_CACHE, Context.MODE_PRIVATE); 
    } 

    @Provides @NonNull @Singleton 
    public Cache getNetworkCache(@NonNull @Named(NETWORK_CACHE) File cacheDir) { 
     int cacheSize = 20 * 1024 * 1024; // 20 MiB 
     return new Cache(cacheDir, cacheSize); 
    } 

    @Provides @NonNull @Singleton 
    public OkHttpClient getHttpClient(@NonNull Cache cache) { 
     return new OkHttpClient.Builder() 
       .cache(cache) 
       .connectTimeout(GLOBAL_TIMEOUT, TimeUnit.SECONDS) 
       .readTimeout(GLOBAL_TIMEOUT, TimeUnit.SECONDS) 
       .writeTimeout(GLOBAL_TIMEOUT, TimeUnit.SECONDS) 
       .build(); 
    } 

MyGameApp

public class MyGameApp extends Application { 

    private AppComponent component; 

    private static Context context; 

    public static MyGameApp get(@NonNull Context context) { 
     return (MyGameApp) context.getApplicationContext(); 
    } 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     component = buildComponent(); 
     MyGameApp.context = getApplicationContext(); 

     } 

    public AppComponent component() { 
     return component; 
    } 

    protected AppComponent buildComponent() { 
     return DaggerAppComponent.builder() 
       .downloaderModule(new DownloaderModule("https://bogus.com/")) 
       .build(); 
    } 

} 
+1

Wie meinst du, "hängt von der Ausgabe des Singleton davor ab?" Es sieht so aus, als ob Ihr Modul gut strukturiert ist, um jedes Stück, das es benötigt, zu injizieren, indem jedes Stück als ein Eingabeparameter in der entsprechenden "@ Provide" -Methode genommen wird. Sie sollten in der Lage sein, 'OkHttpClient' oder eines der anderen Abhängigkeiten, die Sie erstellt haben, in Ihre MyGameActivity zu injizieren. –

+0

Ich habe einfach Schwierigkeiten, es direkt in meinem Kopf zu bekommen. Ich lese noch mehr und die Konzepte sinken. Was frustrierend ist, gibt es Tonnen von Artikeln, die zeigen, wie man es aufstellt, aber tatsächliche Anwendungsbeispiele sind schwer zu finden. Ich arbeite jetzt mit einem anständigen Beispiel. Vielen Dank. –

Antwort

1

Ich werde versuchen, etwas Licht in diese Schuppen, aber es gibt mehrere Möglichkeiten, wie Sie das lesen können. Ich bevorzuge einen Bottom-Up-Ansatz - Beginne grundsätzlich damit, was deine Objekte benötigen und arbeite dich nach oben. In diesem Fall würde ich bei MyGameActivity beginnen. Leider hast du den Code dafür nicht eingefügt, also muss ich etwas kreativ sein, aber das ist ok für den Zweck der Übung.

Also in Ihrer App erhalten Sie wahrscheinlich die AppComponent und inject für Ihre MyGameActivity aufrufen. Also ich denke, diese Aktivität hat einige injizierbare Felder. Ich bin mir nicht sicher, ob Sie dort direkt OkHttpClient verwenden, aber lassen Sie uns sagen, dass Sie es tun. Etwas wie:

public class MyGameActivity extends SomeActivity { 
    @Inject 
    OkHttpClient okHttpClient; 
    // ... 
} 

Die Art, wie ich darüber nachdenken möchte, ist wie folgt. Dolch weiß, dass Sie eine OkHttpClient von der AppComponent angegebenen benötigen. Es wird also untersucht, wie dies bereitgestellt werden kann - Kann es das Objekt selbst erstellen, weil Sie den Konstruktor mit @Inject annotiert haben? Benötigt es mehr Abhängigkeiten ?.

In diesem Fall wird in die Module der Komponente gesucht, in der dieser Client bereitgestellt wird. Es wird getHttpClient erreichen und realisieren, dass es ein Cache Objekt benötigt. Es wird wieder danach suchen, wie dieses Objekt bereitgestellt werden kann - Constructor Injection, eine andere Provider-Methode ?.

Es ist wieder im Modul zur Verfügung gestellt, so dass es getNetworkCache erreichen wird und noch einmal erkennen, es braucht noch eine Abhängigkeit.

Dieses Verhalten wird fortgesetzt, bis es Objekte erreicht, die keine anderen Abhängigkeiten erfordern, wie beispielsweise HttpUrl in getEndpoint.

Nachdem all dies getan ist, kann Ihre OkHttpClient erstellt werden.

Ich denke, es einfach ist, von diesem zu verstehen, warum Sie nicht Zyklen in Ihrem Abhängigkeitsgraphen haben können - Sie können ein Objekt nicht A erstellen, wenn es auf B abhängt und B hängt von A. Stellen Sie sich vor, dass Sie aus irgendeinem seltsamen Grund die Methode getEndpoint erreichen würden, die von der OkHttpClient dieses Moduls abhängt. Das würde nicht funktionieren. Du würdest im Kreis gehen und nie ein Ende erreichen.

Also, wenn ich Ihre Frage verstehe: Wie wird der gesamte Abhängigkeitsgraphen verwendet, ohne jeden Singleton nacheinander aufzurufen, um die erforderlichen Eingaben zu erhalten?

Es ist nicht. Es muss alle Methoden aufrufen, um die Singletons abrufen zu können. Zumindest beim ersten Mal, wenn sie in derselben Komponente/demselben Bereich bereitgestellt werden. Solange Sie dieselbe Instanz Ihrer Komponente beibehalten, geben die Abhängigkeiten mit Bereichsangabe immer die gleiche Instanz zurück. Dolch wird dafür sorgen. Wenn Sie die Komponente aus irgendeinem Grund zerstören oder neu erstellen würden, wären die Abhängigkeiten nicht dieselben. Weitere Informationen here. In der Tat gilt dies für alle Bereiche. Nicht nur @Singleton s.

Allerdings, soweit ich das beurteilen kann, machen Sie es richtig. Wenn Ihre Anwendung erstellt wird, erstellen Sie die Komponente und zwischenspeichern sie. Jedes Mal, wenn Sie die Methode component() verwenden, geben Sie immer die gleiche Komponente zurück und die abhängigen Abhängigkeiten sind immer gleich.

+0

Ich habe es herausgefunden und verwende es. Als ich im Frühjahr die Abhängigkeitsinjektion durchführte, war es schwierig, meinen Denkprozess und die Notwendigkeit, mich selbst einzurichten, durch die Implementierung zu ändern. Dieser Dolch würde so viel mit nur einem einzigen Anruf tun, ist wirklich cool. Ich habe dir eine Antwort für die vollständige Antwort gegeben. –

Verwandte Themen