web-dev-qa-db-ja.com

ダガー2によるプレゼンター注入

Dagger 2を使い始めたばかりですが、オンラインで数千のガイドがそれぞれ異なる実装であることがわかり、今は少し混乱しています。だから基本的にこれは私が現時点で書いたものです:

AppModule.Java:

@Module
public class AppModule {

 Application mApplication;

 public AppModule(Application application) {
    mApplication = application;
 }

 @Provides
 @Singleton
 Application providesApplication() {
    return mApplication;
 }
}

DataModule.Java:

@Module
public class DataModule {

private static final String BASE_URL = "http://beta.fridgewizard.com:9001/api/";

@Provides
@Singleton
NetworkService provideNetworkService() {
    return new NetworkService(BASE_URL);
}

@Provides
@Singleton
SharedPreferences provideSharedPreferences(Application app) {
    return PreferenceManager.getDefaultSharedPreferences(app);
}
}

PrefsModel.Java:

@Module(includes = DataModule.class)
public class PrefsModel {

@Provides
@Singleton
QueryPreferences provideQuery(SharedPreferences prefs) {
    return new QueryPreferences(prefs);
}
}

AppComponent.Java(プレゼンターで必要なため、QueryPreferencesオブジェクトを公開しています。この方法で正しいことを願っています):

@Singleton
@Component(modules = {AppModule.class, DataModule.class, PrefsModel.class})
public interface AppComponent {

    void inject(HomeFragment homeFragment);

    QueryPreferences preferences();
    NetworkService networkService();
}

次に、FwApplication.Javaがあります。

public class FwApplication extends Application {

private static final String TAG = "FwApplication";

private NetworkService mNetworkService;

private AppComponent mDataComponent;

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

       buildComponentAndInject();
    }

    public static AppComponent component(Context context) {
      return ((FwApplication)   context.getApplicationContext()).mDataComponent;
    }

    public void buildComponentAndInject() {
       mDataComponent = DaggerComponentInitializer.init(this);
    }

    public static final class DaggerComponentInitializer {
      public static AppComponent init(FwApplication app) {
        return DaggerAppComponent.builder()
                .appModule(new AppModule(app))
                .dataModule(new DataModule())
                .build();
    }
   }
}

最後に、プレゼンター用に別のモジュールを追加しました。

@Module
public class PresenterModule {

   @Provides
   Presenter<FwView> provideHomePresenter(NetworkService networkService) {
      return new HomePresenterImpl(networkService);
   }

   @Provides
   Presenter<FwView> provideSearchPresenter(NetworkService networkService) {
      return new SearchPresenterImpl(networkService);
   }

}

次のコンポーネント(スコープの依存関係をここに追加できないためエラーが返されます):

@Component(dependencies = AppComponent.class, modules = PresenterModule.class)
public interface PresenterComponent {

    void inject(HomePresenterImpl presenter);
}

したがって、オンラインでドキュメントを読んでいる私にとって明確ではない質問がいくつかあります。

  • AppComponentで定義されたシングルトンであるNetworkServiceに依存しているため、プレゼンターコンポーネントのエラーを修正するにはどうすればよいですか?
  • 「newHomePresenter(networkService)」でHomePresenterを実装する必要があるHomeFragmentがありますが、定義されたDIの使用方法がわかりません。

編集-修正:

HomeFragment.Java:

public class HomeFragment extends Fragment {

private static final String TAG = "FW.HomeFragment";


@Inject
HomePresenterImpl mHomePresenter;

public static HomeFragment newInstance() {
    return new HomeFragment();
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FwApplication.component(getActivity()).inject(this);
}

次に、プレゼンターコンストラクターを次のように変更しました。

@Inject
public HomePresenterImpl(NetworkService networkService) {
    mNetworkService = networkService;
    mInteractor = new InteractorImpl(mNetworkService);
}

次に、NetworkServiceが自動的に挿入されます。

次のコードの上のコードと同じ方法で作成されたプレゼンターを必要とするすべてのフラグメントを呼び出す必要があるので、この方法でそれが正しいかどうか疑問に思っていました。

FwApplication.component(getActivity()).inject(this);
11
user1341300

あなたは物事を混乱させています。プレゼンターを提供するには、次のようなものに切り替える必要があります。

可能であればコンストラクタインジェクションを使用します。それは物事をはるかに簡単にします

public class HomePresenterImpl {

    @Inject
    public HomePresenterImpl(NetworkService networkService) {
        // ...
    }

}

インターフェイスを提供するには、このコンストラクタインジェクションを使用し、実装にdependを使用します。

Presenter<FwView> provideHomePresenter(HomePresenterImpl homePresenter) {
    return homePresenter;
}

このようにして、コンストラクターを自分で呼び出す必要はありません。そして実際にinjectプレゼンターに...

public class MyFragment extends Fragment {

    @Inject
    Presenter<FwView> mHomePresenter;

    public void onCreate(Bundle xxx) {
        // simplified. Add your modules / Singleton component
        PresenterComponent component = DaggerPresenterComponent.create().inject(this);
    }
}

このようにあなたは物を注入します。これをよく読んで理解してください。これにより、主要な問題が修正されますが、同じモジュール(同じスコープ内)から同じタイプの2つのプレゼンターを提供することはできません。

// DON'T
@Provides
Presenter<FwView> provideHomePresenter(NetworkService networkService) { /**/ }

@Provides
Presenter<FwView> provideSearchPresenter(NetworkService networkService) { /**/ }

このは機能しません。同じ種類のオブジェクトを2つ提供することはできません。それらは区別がつかない。見て - @Qualifiers のような@Namedこれがあなたが行きたい方法であると確信しているなら。

13
David Medenjak

コンストラクターで@Injectアノテーションが使用されている場合は、Presenterを指定する必要はありません。クラスのコンストラクターで使用される@Injectアノテーションは、そのクラスを依存性グラフの一部にします。したがって、必要に応じて注入することもできます。

一方、@ Injectアノテーションをフィールドに追加し、コンストラクターには追加しない場合は、そのクラスを提供する必要があります。

5
Mladen Rakonjac