web-dev-qa-db-ja.com

Android Fragments and Servicesでインジェクションをリクエストするにはどうすればよいですか?

このチュートリアル に従って、Dagger 2をAndroidプロジェクトに追加します。

セットアップを行い、モジュールとコンポーネントを作成した後、次のようなアクティビティに依存関係を追加できます。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_account);
    ButterKnife.bind(this);
    ((AppController) getApplication()).getNetComponent().inject(this);
}

FragmentとIntentServiceに依存関係を注入する方法に苦労していますか?

public class FragmentBrandList extends ListFragment {
}

このクラスでは、@Overrideメソッドでインジェクションをリクエストする必要がありますが、このコードは何になりますか?

13
Devesh Agrawal

このクラスでは、どの@Overrideメソッドを使用する必要があり、フラグメントに依存関係を追加するコードは何ですか?

フラグメント内でインジェクションを呼び出す正しい場所は、onAttach(Context context)です。これは、Dagger 2ユーザーガイドのwhere to injectセクションに記載されています here

_@Override
public void onAttach(Context context) {
    ((AppController) context.getApplicationContext()).getNetComponent().inject(this);
    super.onAttach(context);
}
_

サービス内でインジェクションを呼び出す正しい場所はonCreate()です

_@Override 
public void onCreate() {
    ((AppController) getApplication()).getNetComponent().inject(this);
    super.onCreate();

}
_

どちらの場合も、super.onCreate()の呼び出しの前に注入の要求が来ることに注意してください。 Daggerユーザーガイドでは、次のように説明しています。

アクティビティのsuper.onCreate()の前にAndroidInjection.inject()を呼び出すことが重要です。これは、構成の変更中に前のアクティビティインスタンスからフラグメントをスーパーにアタッチし、フラグメントをインジェクトするためです。 Fragmentインジェクションが成功するためには、アクティビティがすでにインジェクトされている必要があります。 ErrorProneのユーザーにとって、super.onCreate()の後にAndroidInjection.inject()を呼び出すのはコンパイラエラーです。

言い換えると:

  1. Activity super.onCreate()呼び出しは、前のインスタンスからフラグメントを再アタッチします
  2. このsuper呼び出しにより、フラグメントが再注入されます(フラグメントはonAttachに注入されるため)
  3. フラグメントは、アクティビティが注入された後に注入する必要があります。したがって、super.onCreate()を呼び出す前にアクティビティに注入を要求してください。

DaggerFragmentDaggerServiceなどの_com.google.dagger:dagger-Android_クラスに関連するソースコードを調べることで、いつどこに挿入するかを確認できます。 GitHubリポジトリはこちら を参照してください

具体的な例として、新しい注入サイトをNetComponentに追加したことを確認してください。

_void inject(FragmentBrandList frag);

void inject(BrandListService service);
_
18
David Rawson

ステップ1:ApplicationModuleを作成する

@Module
public class ApplicationModule {

    private final DIApplication application;

    public ApplicationModule(DIApplication application) {
        this.application = application;
    }

    @Provides @Singleton
    public DIApplication provideApplication() {
        return application;
    }

    @Provides @Singleton
    public DogModel provideDogModel() {
        return new DogModelImpl("Scooby-doo");
    }

}

ステップ2:ApplicationComponentを作成します。

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    void inject(DIApplication application);

    void inject(BaseActivity activity);
    void inject(BaseFragment fragment);

    void inject(DogSyncService service);
}

ステップ3:DIクラスを作成します。

public class DependencyInjector {

    private static ApplicationComponent applicationComponent;

    public static void initialize(DIApplication diApplication) {
        applicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(diApplication))
                .build();
    }

    public static ApplicationComponent applicationComponent() {
        return applicationComponent;
    }

    private DependencyInjector(){}
}

最終ステップ:次を使用してどこにでも注入:

DependencyInjector.applicationComponent()

あなたの質問から、Dagger2を使用してアクティビティ、フラグメント、およびサービスインジェクションを示すデモプロジェクトを作成することになりました。 gitは次のとおりです。 https://github.com/write2sv/AndroidDIDagger2/tree/master/app/src/main/Java/work/shaggy/didemo

7
write2sv

_((AppController) getActivity().getApplication()).getNetComponent().inject(this);_を使用してやった

Fragment.onCreate()メソッド内。

1
Rumid
_((MyApp) context.getApplicationContext()).getApplicationComponent().inject(MyFragment.this);
_

これをフラグメントのonAttach(Context context)メソッドに追加しました。

0
Adi

autodagger2を使用すると、その定型文をすべて記述する必要がなくなります。私はこのアーキテクチャを頻繁に使用します。

build.gradle

apt 'com.github.lukaspili.autodagger2:autodagger2-compiler:1.1'
compile 'com.github.lukaspili.autodagger2:autodagger2:1.1'

YourApp.Java

@AutoComponent( modules = YourApp.YourAppModule.class )
public class YourApp extends Application {

    private static YourApp instance;
    private YourAppComponent component;

    public YourAppComponent getComponent() {
        return this.component;
    }

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

        setupComponent();
    }

    private void setupComponent() {
        component = DaggerYourAppComponent.builder()
                .yourAppModule(new YourAppModule(instance))
                .build();
    }


    @dagger.Module
    public static class YourAppModule {
        private YourApp app;

        YourAppModule(YourAppApp application) {
            this.app = application;
        }

        @Provides @AutoExpose(YourApp.class)
        Application provideApplication() {
            return app;
        }

        @Provides @AutoExpose(PoswalaApp.class)
        Context provideContext() {
            return app;
        }

        @Provides @AutoExpose(YourApp.class)
        Retrofit provideApiAdapter() {
            return ApiService.getServiceInstance();
        }
    }
}

YourActivity.Java

@AutoComponent(
    dependencies = YourApp.class,
    modules = YourActivity.YourActivityModule.class
)

public class YourActivity extends BaseActivity implements YourActivityView {

    private YourActivityComponent component;
    @Inject MyPresenter presenter

    // This is an abstract method from BaseActivity
    @Override
    protected void setupComponent(YourAppComponent appComponent) {
        component = DaggerYourActivityComponent.builder()
                .yourAppComponent(((YourApp) getApplication()).getComponent())
                .yourActivityModule(new YourctivityModule(this))
                .build();
    }

    @Override
    protected MyPresenter getPresenter() {
        return presenter;
    }


    @dagger.Module
    public static class YourActivityModule {

        private YourActivityView view;

        YourActivityModule(YourActivityView view) {
            this.view = view;
        }


        @Provides @AutoExpose(YourActivity.class)
        YourActivityView provideView() {
            return view;
        }

        // Your other dependencies
    }
}

簡単な説明:

アプリのモジュールは「ユニバーサル」な依存関係を持つ必要がありますが、この方法では、クラスに複数のモジュールを使用して達成できます。あなただけをカスタマイズする必要があります

@AutoComponent(
    dependencies = YourApp.class,
    modules = { YourActivity.YourActivityModule.class, YourFragment.YourFragmentModule.class }
)

ブロック。その構文を使用して、好きなだけモジュールを追加できます。

これがあなたを助けることを願っています

0
Chisko

あなたは本当にあなたが注入したいもののためにインジェクタメソッドを含める必要があります。

@Singleton
@Component
public interface AppComponent {
    void inject(MainActivity activity);
    void inject(FragmentBrandList fragmentBrandList);
} 
0
EpicPandaForce