4

私が見た限られた例以外で、Dagger 2.0 を使用する方法を理解するのに苦労しています。読み取りアプリケーションの例を見てみましょう。この読書アプリには、ユーザーのストーリーとログイン機能のライブラリがあります。この例の目的で関心のあるクラスは次のとおりです。

MainApplication.java- アプリケーションを拡張

LibraryManager.java- ユーザーのライブラリでストーリーの追加/削除を担当するマネージャー。これは、MainApplication

AccountManager.java- すべてのユーザーのログイン情報を保存する責任がある管理者。LibraryManager から呼び出すことができます。

どのコンポーネントとモジュールを作成する必要があるのか​​、まだ頭を悩ませています。これまでに収集できるものは次のとおりです。

andインスタンスHelperModuleを提供する を作成します。AccountManagerLibraryManager

@Module
public class HelperModule {

    @Provides
    @Singleton
    AccountManager provideAccountManager() {
        return new AccountManager();
    }

    @Provides
    @Singleton
    LibraryManager provideLibraryManager() {
        return new LibraryManager();
    }

}

モジュールのリストにMainApplicationComponentをリストする を作成します。HelperModule

@Singleton
@Component(modules = {AppModule.class, HelperModule.class})
public interface MainApplicationComponent {
    MainApplication injectApplication(MainApplication application);
}

に含め@Injects LibraryManager libraryManagerMainApplication、アプリケーションをグラフに挿入します。最後に、注入さLibraryManagerれたライブラリ内のストーリーの数を照会します。

public class MainApplication extends Application {

    @Inject LibraryManager libraryManager;

    @Override
    public void onCreate() {
        super.onCreate();

        component = DaggerMainApplicationComponent.builder()
                .appModule(new AppModule(this))
                .helperModule(new HelperModule())
                .build();
        component.injectApplication(this);

        // Now that we have an injected LibraryManager instance, use it
        libraryManager.getLibrary();
    }
}

に注入AccountManagerするLibraryManager

public class LibraryManager {
    @Inject AccountManager accountManager;

    public int getNumStoriesInLibrary() {
        String username = accountManager.getLoggedInUserName();
        ...
    }
}

ただし、問題は、でAccountManager使用しようとすると null でありLibraryManager、問​​題を解決する理由や方法がわかりません。グラフに注入された が AccountManager を直接使用していないためだと思いますが、どのようにグラフMainApplicationに注入する必要がありLibraryManagerますか?

4

3 に答える 3

7

クラスを次のように変更すると、機能します。

あなたの POJO:

public class LibraryManager {
    @Inject AccountManager accountManager;

    public LibraryManager(){
        MainApplication.getComponent().inject(this);
    }

    public int getNumStoriesInLibrary() {
        String username = accountManager.getLoggedInUserName();
        ...
    }

    ...
}

コンポーネント インターフェイス:

 @Singleton
 @Component(modules = {AppModule.class, HelperModule.class})
    public interface MainApplicationComponent {
        void inject(MainApplication application);
        void inject(LibraryManager lm);
    }
 }

あなたのアプリケーション クラス:

public class MainApplication extends Application {
    private static MainApplicationComponent component;

    @Inject LibraryManager libraryManager;

    @Override
    public void onCreate() {
        super.onCreate();

        component = DaggerMainApplicationComponent.builder()
                .appModule(new AppModule(this))
                .helperModule(new HelperModule())
                .build();
        component.injectApplication(this);

        // Now that we have an injected LibraryManager instance, use it
        libraryManager.getLibrary();
    }

    public static MainApplicationComponent getComponent(){return component;}


}

実際、すべての依存クラスに対して同じことを行う必要があります。基本的に、すべてのアクティビティ サブクラスでアプリケーション クラスにアクセスできるため、get コンポーネントを静的メソッドとして作成することは重要です。しかし、POJO の場合は、何らかの方法でコンポーネントをキャッチする必要があります。実装する方法はたくさんあります。これは、それがどのように機能するかを示すための単なる図です。これで火星を破壊できます:)

于 2015-11-16T10:55:42.630 に答える
1

私はかなり良い解決策を思いついたと思います。AccountManagerに を注入しようとする代わりにLibraryManager、 に を提供しAccountManager、その方法MainApplicationComponentでアクセスしてLibraryManagerいます。

MainApplicationComponent:

@Singleton
@Component(modules = {AppModule.class, HelperModule.class})
public interface MainApplicationComponent {
    MainApplication injectApplication(MainApplication application);

    // Provide the managers here so all classes that have a pointer to the MainApplicationComponent can access them.
    // This avoids having to pass each manager to the constructor of all classes that need them
    AccountManager accountManager();
    ArchiveManager archiveManager();
}

インスピレーションのためにサンプル Android アプリ ( https://github.com/gk5885/dagger-android-sample ) を使用して、HasComponent インターフェイスを作成しました。

public interface HasComponent<C> {
    C getComponent();
}

MainApplication にインターフェイスを実装させました。また、HelperModule を作成するときに、モジュールがコンポーネントにアクセスできるようにこれを渡すことに気付くでしょう。

public class MainApplication extends Application implements HasComponent<MainApplicationComponent>{

    MainApplicationComponent mainApplicationComponent;

    @Override
    public MainApplicationComponent getComponent() {
        return mainApplicationComponent;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        component = DaggerMainApplicationComponent.builder()
                .appModule(new AppModule(this))
                .helperModule(new HelperModule(this))
                .build();
        component.injectApplication(this);

        // Now that we have an injected LibraryManager instance, use it
        mainApplicationComponent.libraryManager().getLibrary();
    }
}

LibraryManager が変更され、HasComponent をコンストラクターのパラメーターとして受け取るようになりました。

public class LibraryManager {

    AccountManager accountManager;
    public ArchiveManager(HasComponent<MainApplicationComponent> hasComponent) {
        accountManager = hasComponent.getComponent().accountManager();
    }
    ...
}

最後に、HelperModule では、実装をHasComponent<MainApplicationComponent>LibraryManager のコンストラクターに渡すだけです。

@Module
public class HelperModule {

private HasComponent<WattpadComponent> hasComponent;

public HelperModule(HasComponent<WattpadComponent> hasComponent) {
    this.hasComponent = hasComponent;
}

@Provides
@Singleton
AccountManager provideAccountManager() {
    return new AccountManager(hasComponent);
}

@Provides
@Singleton
ArchiveManager provideLibraryManager() {
    return new LibraryManager(hasComponent);
}

}

これにより、単体テストも非常に簡単になります。の単体テストを行っていてLibraryManager、 をモックアウトしたい場合は、 MainApplicationComponent を拡張AccountManagerする を作成し、モックを提供してのコンストラクターに渡すモジュールのリストに を含めるだけです。TestMainApplicationComponentTestHelperModuleAccountManagerTestMainApplicationComponentLibraryManager

私はダガーを初めて使用するので、何か不足している可能性がありますが、単体テスト以外はすべて試しましたが、これまでのところ機能しているようです。興味のある方のために、ユニットテストの例を含む GitHub リンクをまもなく投稿します。

コンポーネントがオブジェクトをインスタンス化する方法をよりよく理解するための@Kirillの回答に感謝します。

于 2015-04-14T19:53:41.893 に答える