2017-12-21 8 views
1

Ich baue eine App mit einigen Features: ein ContentProvider ein SyncAdapter, ein Job-Service und verwandte Persistenz Logik. Hinzu kommen die Aktivitäten mit der Benutzeroberfläche. Ich versuche, alle genannten Features in ein separates Bibliotheksmodul zu integrieren, da ihre Logik theoretisch eigenständig und für jede Anwendung wiederverwendbar ist.Injizieren Anwendungskontext in Bibliothek Modul mit Dolch 2

Jetzt kommt Dagger2. Der erste Knoten (Hauptkomponente) des Abhängigkeitsgraphen meiner Bibliothek muss Kontext bereitstellen, und dieser Kontext muss von der Anwendung aus injiziert werden, da der Bibliotheksbereich den gleichen Lebenszyklus der Anwendung aufweist. Um offensichtlich eigenständig zu sein, sollte meine Bibliothek meine Anwendungsklasse nicht direkt verwenden.

Dies sind die Möglichkeiten, die ich gedacht:

  • die Hauptkomponente der Bibliothek bauen in meiner Anwendung und speichern sie in einer globalen statischen Klasse/Enum als here vorgeschlagen, aber ich bin besorgt, dass eine statische Referenz solche mit könnte ein Anti-Muster sein.
  • Packen Sie in der Bibliothek eine Application-Klasse, die die bibliotheksspezifische Komponente erstellt, umwandeln Sie den App-Kontext zu dieser Klasse in der Bibliothek, um die Komponente zu verwenden, und erweitern Sie dann diese Application-Klasse in der Hauptanwendung. Das funktioniert, aber wenn es mehr als eine Bibliothek gibt, ist es nicht mehr lebensfähig.
  • Verwenden Sie das Factory-Muster: Setzen Sie Provisionierungsmethoden in die Bibliothekskomponente, die die Factory bereitstellt, die wiederum den lokal verfügbaren Kontext als Parameter erhält. (Wie erklärt here). Dies erscheint möglich, obwohl es zusätzliche Komplexität hinzufügt.
  • Last but not least, geben Sie es auf, die Komponenten zu modularisieren, da abhängig vom Kontext der Anwendung das Konzept der Modularität bricht.

Was ist der richtige Weg, dies zu tun?

+0

Ich möchte das gleiche tun. Hast du eine Lösung gefunden? –

+0

Ich habe diese Frage vergessen :) Ich habe eine Lösung gefunden, siehe meine Antwort unten. – devrocca

Antwort

1

Dagger 2 for Android kommt zur Rettung. Es bietet das Konzept AndroidInjector, das eine Component ist, die verwendet werden kann, um eine Instanz auf eine statische Weise zu injizieren, ohne den Abhängigkeitsanbieter kennen zu müssen. Darüber hinaus sehen die injizierten Abhängigkeiten bei Verwendung der vordefinierten Klassen, die standardmäßig mitgeliefert werden, wie aus dem Nichts kommend vor. Genial.

Alles, was Sie tun müssen, ist in der Bibliothek eine Top-Level Module zu deklarieren, die in der Anwendung Component installiert ist. Diese Module stellt alle Abhängigkeiten und die von der Bibliothek benötigten SubComponent s bereit, die automatisch die @AppContext Context, die Sie im Abhängigkeitsdiagramm festgelegt haben, erben, die überall in Ihrer Bibliothek injiziert werden kann, sowie jede Abhängigkeit, die Sie über die Hauptanwendung bereitstellen Component.

Hier ist ein kurzes Beispiel (geschrieben in Kotlin):

@Component(modules = [ 
    AndroidSupportInjectionModule::class, 
    AppModule::class, 
    LibraryModule::class //plug-in the library to the dependency graph 
]) 
@Singleton 
interface AppComponent : AndroidInjector<App> { 

    @Component.Builder 
    abstract class Builder : AndroidInjector.Builder<App>() { 

     @BindsInstance 
     abstract fun appContext(@AppContext context: Context) 

     override fun seedInstance(instance: App) { 
      appContext(instance) 
     } 
    } 
} 

Edit: erweiterte Beispiele

Ein Beispiel für die Anwendungsunterklasse:

// DaggerApplication provides out-of-the-box support to all the AndroidInjectors. 
// See the class' code to understand the magic. 
public class App extends DaggerApplication { 

@Override 
protected AndroidInjector<? extends DaggerApplication> applicationInjector() { 
    // We only provide its own Injector, the Application Injector, 
    // that is the previous AppComponent 
    return DaggerAppComponent.builder().create(this); 
} 

Und in Ihrem Android-Bibliothek :

@Module 
public abstract class LibraryModule { 

    @ContributesAndroidInjector 
    public abstract LibraryActivity contributeLibraryActivityInjector(); 

} 

public class LibraryActivity extends DaggerAppCompatActivity { 

    @Inject 
    @AppContext 
    Context appContext; 

    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceSate); 
     // here you automagically have your injected application context! 
     ExternalSingleton.getInstance(appContext) 
    } 
} 
+0

Im Allgemeinen sollten Frameworks zur Abhängigkeitsinjektion nicht in Bibliotheken verwendet werden - sie sind Tools auf Anwendungsebene. Warum möchten Sie die Klassen innerhalb der Bibliothek mit Dagger innerhalb der Bibliothek verfügbar machen? Machen Sie die Klassen einfach öffentlich (oder extrahieren Sie eine Fassade) und fügen Sie sie dem Objektgraphen in der Anwendung anstatt in der Bibliothek hinzu. – Vasiliy

+0

@Vasiliy Was ist, wenn ich ein Bibliotheksmodul habe, das einen Android-Kontext benötigt (z. B. Dateispeicher, Caching usw.)? Warum wäre es eine schlechte Idee, DI in diesem Fall zu verwenden? –

+0

@devrocca Ohne eine Application-Klasse in Ihrem Modul, wie haben Sie implementiert ** HasActivityInjector ** –

Verwandte Themen