web-dev-qa-db-ja.com

AndroidプロジェクトでDAGGER依存関係注入をゼロから設定する方法は?

Daggerの使用方法私のAndroidプロジェクトで動作するようにDaggerを構成する方法?

AndroidプロジェクトでDaggerを使用したいのですが、わかりにくいです。

編集:Dagger2も2015年4月15日からリリースされており、さらに混乱しています!

[この質問は "スタブ"であり、Dagger1についてさらに学び、Dagger2についてさらに学びながら、答えに追加しています。この質問は、「質問」ではなく、ガイドです。]

96
EpicPandaForce

Dagger 2.x(改訂版6)のガイド:

手順は次のとおりです。

1.)Daggerを_build.gradle_ファイルに追加します。

  • トップレベルbuild.gradle

_// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.Android.tools.build:gradle:2.2.0'
        classpath 'com.neenbedankt.gradle.plugins:Android-apt:1.8' //added apt for source code generation
    }
}

allprojects {
    repositories {
        jcenter()
    }
}
_
  • アプリレベルbuild.gradle

_apply plugin: 'com.Android.application'
apply plugin: 'com.neenbedankt.Android-apt' //needed for source code generation

Android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "your.app.id"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.Android.support:appcompat-v7:24.2.1'
    compile 'com.google.dagger:dagger:2.7' //dagger itself
    provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}
_

2.)依存関係を提供するAppContextModuleクラスを作成します。

_@Module //a module could also include other modules
public class AppContextModule {
    private final CustomApplication application;

    public AppContextModule(CustomApplication application) {
        this.application = application;
    }

    @Provides
    public CustomApplication application() {
        return this.application;
    }

    @Provides 
    public Context applicationContext() {
        return this.application;
    }

    @Provides
    public LocationManager locationService(Context context) {
        return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    }
}
_

3.)注入可能なクラスを取得するためのインターフェースを提供するAppContextComponentクラスを作成します。

_public interface AppContextComponent {
    CustomApplication application(); //provision method
    Context applicationContext(); //provision method
    LocationManager locationManager(); //provision method
}
_

3.1.)これは、実装を使用してモジュールを作成する方法です。

_@Module //this is to show that you can include modules to one another
public class AnotherModule {
    @Provides
    @Singleton
    public AnotherClass anotherClass() {
        return new AnotherClassImpl();
    }
}

@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
    @Provides
    @Singleton
    public OtherClass otherClass(AnotherClass anotherClass) {
        return new OtherClassImpl(anotherClass);
    }
}

public interface AnotherComponent {
    AnotherClass anotherClass();
}

public interface OtherComponent extends AnotherComponent {
    OtherClass otherClass();
}

@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
    void inject(MainActivity mainActivity);
}
_

注意::モジュールの_@Scope_に_@Singleton_注釈(_@ActivityScope_または_@Provides_など)を指定する必要がありますアノテーション付きメソッドを使用して、生成されたコンポーネント内でスコーププロバイダーを取得します。そうしないと、スコープが限定され、注入するたびに新しいインスタンスが取得されます。

3.2.)注入できるものを指定するアプリケーションスコープのコンポーネントを作成します(これはDagger 1.xの_injects={MainActivity.class}_と同じです)。

_@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
    void inject(MainActivity mainActivity);
}
_

3.3.)can自分でコンストラクタを介して作成し、_@Module_を使用して再定義したくない依存関係の場合(forたとえば、代わりにビルドフレーバーを使用して実装のタイプを変更します)、_@Inject_注釈付きコンストラクターを使用できます。

_public class Something {
    OtherThing otherThing;

    @Inject
    public Something(OtherThing otherThing) {
        this.otherThing = otherThing;
    }
}
_

また、_@Inject_コンストラクターを使用する場合、component.inject(this)を明示的に呼び出す必要なく、フィールドインジェクションを使用できます。

_public class Something {
    @Inject
    OtherThing otherThing;

    @Inject
    public Something() {
    }
}
_

これらの_@Inject_コンストラクタークラスは、モジュールで明示的に指定することなく、同じスコープのコンポーネントに自動的に追加されます。

_@Singleton_スコープの_@Inject_コンストラクタークラスは、_@Singleton_スコープのコンポーネントに表示されます。

_@Singleton // scoping
public class Something {
    OtherThing otherThing;

    @Inject
    public Something(OtherThing otherThing) {
        this.otherThing = otherThing;
    }
}
_

3.4.)次のように、特定のインターフェイスの特定の実装を定義した後:

_public interface Something {
    void doSomething();
}

@Singleton
public class SomethingImpl {
    @Inject
    AnotherThing anotherThing;

    @Inject
    public SomethingImpl() {
    }
}
_

_@Module_を使用して、特定の実装をインターフェイスに「バインド」する必要があります。

_@Module
public class SomethingModule {
    @Provides
    Something something(SomethingImpl something) {
        return something;
    }
}
_

Dagger 2.4以降の短縮形は次のとおりです。

_@Module
public abstract class SomethingModule {
    @Binds
    abstract Something something(SomethingImpl something);
}
_

4.)Injectorクラスを作成して、アプリケーションレベルのコンポーネントを処理します(モノリシックObjectGraphを置き換えます)

(注:APTを使用してDaggerApplicationComponentビルダークラスを作成する_Rebuild Project_)

_public enum Injector {
    INSTANCE;

    ApplicationComponent applicationComponent;

    private Injector(){
    }

    static void initialize(CustomApplication customApplication) {
        ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
           .appContextModule(new AppContextModule(customApplication))
           .build();
        INSTANCE.applicationComponent = applicationComponent;
    }

    public static ApplicationComponent get() {
        return INSTANCE.applicationComponent;
    }
}
_

5.)CustomApplicationクラスを作成

_public class CustomApplication
        extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Injector.initialize(this);
    }
}
_

6.)CustomApplicationを_AndroidManifest.xml_に追加します。

_<application
    Android:name=".CustomApplication"
    ...
_

7.)クラスをMainActivityに挿入する

_public class MainActivity
        extends AppCompatActivity {
    @Inject
    CustomApplication customApplication;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Injector.get().inject(this);
        //customApplication is injected from component
    }
}
_

8。)お楽しみください!

+1。)作成できるコンポーネントにScopeを指定できますActivity-level scoped components。サブスコープを使用すると、アプリケーション全体ではなく、特定のサブスコープにのみ必要な依存関係を提供できます。通常、各アクティビティはこのセットアップで独自のモジュールを取得します。スコーププロバイダーが存在することに注意してくださいコンポーネントごと、つまり、そのアクティビティのインスタンスを保持するためには、コンポーネント自体が構成の変更に耐えなければなりません。たとえば、onRetainCustomNonConfigurationInstance()またはMortarスコープを介して存続できます。

サブスコープの詳細については、 ガイドby Google をご覧ください。また、 このサイトのプロビジョニング方法 および コンポーネントの依存関係セクション )および here もご覧ください。 。

カスタムスコープを作成するには、スコープ修飾子の注釈を指定する必要があります。

_@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}
_

サブスコープを作成するには、コンポーネントのスコープを指定し、その依存関係としてApplicationComponentを指定する必要があります。モジュールプロバイダーメソッドでもサブスコープを指定する必要があることは明らかです。

_@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
        extends ApplicationComponent {
    CustomScopeClass customScopeClass();

    void inject(YourScopedClass scopedClass);
}
_

そして

_@Module
public class CustomScopeModule {
    @Provides
    @YourCustomScope
    public CustomScopeClass customScopeClass() {
        return new CustomScopeClassImpl();
    }
}
_

oneスコープコンポーネントのみを依存関係として指定できることに注意してください。 Javaで多重継承がサポートされていないのとまったく同じように考えてください。

+2.) _@Subcomponent_について:基本的に、スコープ付きの_@Subcomponent_はコンポーネントの依存関係を置き換えることができます。ただし、注釈プロセッサが提供するビルダーを使用するのではなく、コンポーネントファクトリメソッドを使用する必要があります。

したがって、この:

_@Singleton
@Component
public interface ApplicationComponent {
}

@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
        extends ApplicationComponent {
    CustomScopeClass customScopeClass();

    void inject(YourScopedClass scopedClass);
}
_

これになります:

_@Singleton
@Component
public interface ApplicationComponent {
    YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}

@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
    CustomScopeClass customScopeClass();
}
_

この:

_DaggerYourCustomScopedComponent.builder()
      .applicationComponent(Injector.get())
      .customScopeModule(new CustomScopeModule())
      .build();
_

これになります:

_Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
_

+3.): Dagger2に関する他のStack Overflowの質問も確認してください。多くの情報が提供されています。たとえば、現在のDagger2構造は this answer で指定されています。

ありがとう

GithubTutsPlusJoe SteeleFroger MCS および Google

また、この ステップバイステップの移行ガイドについては、この投稿を書いた後に見つけました。

また、 スコープの説明 についてはキリル。

公式ドキュメンテーション のさらに詳しい情報。

181
EpicPandaForce

Dagger 1.xのガイド:

手順は次のとおりです。

1.)Daggerを依存関係の_build.gradle_ファイルに追加します

_dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    ...
    compile 'com.squareup.dagger:dagger:1.2.2'
    provided 'com.squareup.dagger:dagger-compiler:1.2.2'
_

また、_packaging-option_に関するエラーを防ぐために_duplicate APKs_を追加します。

_Android {
    ...
    packagingOptions {
        // Exclude file to avoid
        // Error: Duplicate files during packaging of APK
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
}
_

2.)Injectorクラスを作成して、ObjectGraphを処理します。

_public enum Injector
{
    INSTANCE;

    private ObjectGraph objectGraph = null;

    public void init(final Object rootModule)
    {

        if(objectGraph == null)
        {
            objectGraph = ObjectGraph.create(rootModule);
        }
        else
        {
            objectGraph = objectGraph.plus(rootModule);
        }

        // Inject statics
        objectGraph.injectStatics();

    }

    public void init(final Object rootModule, final Object target)
    {
        init(rootModule);
        inject(target);
    }

    public void inject(final Object target)
    {
        objectGraph.inject(target);
    }

    public <T> T resolve(Class<T> type)
    {
        return objectGraph.get(type);
    }
}
_

3.)RootModuleを作成して、将来のモジュールをリンクします。 _@Inject_アノテーションを使用するすべてのクラスを指定するには、injectsを含める必要があることに注意してください。そうしないと、DaggerがRuntimeExceptionをスローします。

_@Module(
    includes = {
        UtilsModule.class,
        NetworkingModule.class
    },
    injects = {
        MainActivity.class
    }
)
public class RootModule
{
}
_

4.)ルートで指定されたモジュール内に他のサブモジュールがある場合、それらのモジュールを作成します:

_@Module(
    includes = {
        SerializerModule.class,
        CertUtilModule.class
    }
)
public class UtilsModule
{
}
_

5.)依存関係をコンストラクターパラメーターとして受け取るリーフモジュールを作成します。私の場合、循環依存関係はなかったので、Daggerがそれを解決できるかどうかはわかりませんが、ありそうにないと思います。 _complete = false_を指定した場合、コンストラクタパラメータもDaggerによってモジュールで提供する必要があります。他のモジュールでも使用できます。

_@Module(complete = false, library = true)
public class NetworkingModule
{
    @Provides
    public ClientAuthAuthenticator providesClientAuthAuthenticator()
    {
        return new ClientAuthAuthenticator();
    }

    @Provides
    public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator)
    {
        return new ClientCertWebRequestor(clientAuthAuthenticator);
    }

    @Provides
    public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor)
    {
        return new ServerCommunicator(clientCertWebRequestor);
    }
}
_

6.)Applicationを拡張し、Injectorを初期化します。

_@Override
public void onCreate()
{
    super.onCreate();
    Injector.INSTANCE.init(new RootModule());
}
_

7.)MainActivityで、onCreate()メソッドでインジェクターを呼び出します。

_@Override
protected void onCreate(Bundle savedInstanceState)
{
    Injector.INSTANCE.inject(this);
    super.onCreate(savedInstanceState);
    ...
_

8.)MainActivityで_@Inject_を使用します。

_public class MainActivity extends ActionBarActivity
{  
    @Inject
    public ServerCommunicator serverCommunicator;

...
_

エラー_no injectable constructor found_を受け取った場合は、_@Provides_注釈を忘れていないことを確認してください。

11
EpicPandaForce

ここで便利なDagger2サンプルプロジェクトとチュートリアルを見つけることができます。

MVPを使用したダガー2作業サンプルプロジェクト

ビデオチュートリアル

実践的なチュートリアル

0