简体   繁体   中英

How do I request injection in Android Fragments and Services?

I'm following this tutorial to add Dagger 2 to my Android project.

After doing setup and creating the modules and components I can add the dependencies in an Activity like this:

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

I am struggling in how to inject dependencies in a Fragment and IntentService?

public class FragmentBrandList extends ListFragment {
}

In this class which @Override method should I request injection in and what will be the code for this?

In this class which @Override method i should use and what will be the code to add dependency in fragment?

The correct place to call injection inside a Fragment is onAttach(Context context) . This is stated in the where to inject section of the Dagger 2 user guide here

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

The correct place to call injection inside a Service is onCreate()

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

}

Note that in both cases the request for injection comes before the call to super.onCreate() . The Dagger user guide explains it like this:

It is crucial to call AndroidInjection.inject() before super.onCreate() in an Activity, since the call to super attaches Fragments from the previous activity instance during configuration change, which in turn injects the Fragments. In order for the Fragment injection to succeed, the Activity must already be injected. For users of ErrorProne, it is a compiler error to call AndroidInjection.inject() after super.onCreate().

In other words:

  1. The Activity super.onCreate() call re-attaches Fragments from a previous instance
  2. This super call in cause Fragments to be re-injected (since Fragments are injected in onAttach )
  3. Fragments should be injected after their Activity is injected, therefore request injection in your Activity before calling super.onCreate() .

You can always check where to inject by looking at the relevant source code for the com.google.dagger:dagger-android classes like DaggerFragment and DaggerService . See the GitHub repo here

For your specific example, please make sure you have added the new injection sites to the NetComponent:

void inject(FragmentBrandList frag);

void inject(BrandListService service);

Step 1: Create your 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");
    }

}

Step 2: Create your 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);
}

Step 3: Create a DI Class:

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

Final Step: Inject anywhere using:

DependencyInjector.applicationComponent()

Your question inspired me to create a Demo project that shows Activity, Fragment and Service injection using Dagger2. Here is the git: https://github.com/write2sv/AndroidDIDagger2/tree/master/app/src/main/java/work/shaggy/didemo

I did it using ((AppController) getActivity().getApplication()).getNetComponent().inject(this);

in Fragment.onCreate() method.

You can use autodagger2 to avoid having to write all that boilerplate. I use this architecture quite often:

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
    }
}

Quick explanation:

Your app's module will have to a "universal" dependency, but this way you can achieve using several modules for a class. You just need to customize the

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

block. You can add as many modules as you like using that syntax.

Hope this helps you

You really just need to include the injector method for whatever you want to inject.

@Singleton
@Component
public interface AppComponent {
    void inject(MainActivity activity);
    void inject(FragmentBrandList fragmentBrandList);
} 
((MyApp) context.getApplicationContext()).getApplicationComponent().inject(MyFragment.this);

我在onAttach(Context context)方法中添加了这个。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM