2017-12-21 18 views
1

私はいくつかの機能を持つアプリケーションを構築しています:ContentProvider、SyncAdapter、Jobサービス、および関連する永続ロジック。これらの上に、UIのアクティビティがあります。理論的には、ロジックは独立型であり、どのアプリケーションでも再利用できるので、私はこれらのすべての機能を別々のライブラリモジュールに入れようとしています。ダガー2でライブラリモジュールにアプリケーションコンテキストを注入する

今すぐDagger2が来ます。私のライブラリ依存グラフの最初のノード(メインコンポーネント)はContextを提供する必要があり、ライブラリスコープのライフサイクルがアプリケーションのライフサイクルと同じであるため、このコンテキストをアプリケーションから注入する必要があります。明らかに私のライブラリは私のアプリケーションクラスを直接使うべきではありません。 hereが示唆したように、私のアプリケーションでは、ライブラリの主なコンポーネントを構築し、グローバルな静的クラス/列挙型に格納し

  • が、私は、このような静的な参照を使用していることを心配:

    これらは私が考える可能性があります反パターンになる可能性があります。

  • ライブラリには、ライブラリスコープのコンポーネントを作成するアプリケーションクラス、ライブラリ内のこのクラスにアプリケーションコンテキストをキャストしてコンポーネントを使用し、メインアプリケーションでこのアプリケーションクラスを拡張するApplicationクラスがあります。これはうまくいきますが、複数のライブラリがあれば、もはや実行可能ではありません。
  • ファクトリパターンを使用します。ローカルに使用可能なコンテキストがパラメータとして指定されたファクトリを提供するライブラリコンポーネントにプロビジョニングメソッドを配置します。 (説明したようにhere)。これは余分な複雑さを追加するが、実行可能なようだ。
  • 最後に、アプリケーションのコンテキストに依存するため、モジュール化の概念が破綻するため、コンポーネントをモジュール化しようとするのをやめてください。

これを行う正しい方法は何ですか。

+0

私は同じことをしたいと思います。あなたは解決策を見つけましたか? –

+0

私はこの質問を忘れてしまった:)私は解決策を見つけた、私の答えは以下を参照してください。 – devrocca

答えて

1

Dagger 2 for Androidが救助になります。 AndroidInjectorのコンセプトを提供します。これは、従属性プロバイダを知らなくても、静的な方法でインスタンスを挿入するために使用できるComponentです。さらに、ボックスの外に用意されている接頭辞付きのクラスDagger-を使用すると、注入された依存関係はどこからも来ないように見えます。驚くばかり。

アプリケーションComponentにインストールされているトップレベルModuleを宣言するだけでいいです。このModuleはライブラリに必要なすべての依存関係とSubComponentを提供します。これは依存関係グラフにシードした@AppContext Contextを自動的に継承し、ライブラリ内のどこにでも注入できる状態になります。また、メインアプリケーションを通じて提供するすべての依存関係Component。ここで

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

編集:拡張例

アプリケーションのサブクラスの例:

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

そして、あなたのAndroidのライブラリで:

@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

一般に、依存性注入フレームワークはライブラリ内で使用すべきではありません。これらはアプリケーションレベルのツールです。ライブラリ内のDaggerを使用して、ライブラリ内のクラスを公開したいのはなぜですか?クラスをパブリック(または1つのファサードを抽出)にして、libの代わりにアプリケーションのオブジェクトグラフに追加するだけです。 – Vasiliy

+0

@Vasiliy Androidのコンテキスト(ファイルの保存、キャッシュなど)が必要なライブラリモジュールを持っているとどうなりますか?なぜこのような場合にDIを使用するのは悪い考えですか? –

+0

@devroccaあなたのモジュールにApplicationクラスがなければ、どのように** HasActivityInjector **を実装しましたか? –

関連する問題