In my efforts to follow the good and official advice for injecting and avoiding cumbersome code (which I had) from the authors themselves, I ran into a wall when trying to use the support library.
According to the article:
AppCompat users should continue to implement
AndroidInjector.Factory<? extends Activity> and not <? extends AppCompatActivity>
(orFragmentActivity
).
I'm sticking to an MVP architecture where views are always Fragment
s and I don't want to involve my Activity
in any DI business, but I wonder if it's necessary for this to work but so far I haven't been able to. If I skip the whole support thing, the app crashes at runtime because the instance of the fragment is support (in case it's not obvious). Then I went into the task of trying to try to implement HasSupportFragmentInjector
instead of HasFragmentInjector
with a whole bunch of changes due to compile errors my mind has forgotten for the sake of my mental health. After a while I come to a point of thinking how can a non-support Activity host a support fragment. Ah! Those tricky wildcards. But no matter how I've tried to follow the advice, I can't come up with a way without an EmptyModule
that I also would need to setup in the Activity so it would be visible to the fragment by dagger and its (really, for me still, magic). Why I haven't tried it? I might as well have, but I'm tired of hopeless changes and I need help at this point.
AppModule.kt
@Singleton
@dagger.Module
class AppModule(val application: Application) {
@Provides @Singleton fun application(): Application = application
...
}
AppComponent.java
@ApplicationScope
@Singleton
@Component(modules = {
AndroidSupportInjectionModule.class,
...
FooFragmentModule.class,
})
public interface AppComponent {
Application app();
...
void inject(MyApp app);
}
MyApp.java
public class MyApp extends Application implements HasActivityInjector {
private AppComponent component;
public AppComponent someWayToReturnAppComponent() {
...
}
@Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
@Override
public void onCreate() {
component = DaggerAppComponent.builder()
.appModule(new AppModule(this))
// more app-scoped modules
.build();
component.inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
}
MainActivity.java
public abstract class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout()); // inflate the fragment via XML here
}
@Inject DispatchingAndroidInjector<Fragment> dispatchingFragmentInjector;
@Override
public AndroidInjector<Fragment> fragmentInjector() {
return dispatchingFragmentInjector;
}
}
FooFragmentComponent.java
@Subcomponent
public interface FooFragmentComponent extends AndroidInjector<FooFragment> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<FooFragment> {}
}
FooFragmentModule.kt
@dagger.Module(subcomponents = {FooFragmentComponent.class})
public abstract class FooFragmentModule {
@Binds
@IntoMap
@FragmentKey(FooFragment.class)
abstract AndroidInjector.Factory<? extends Fragment> bindFragmentInjectorFactory(FooFragmentComponent.Builder builder);
@ActivityScope
abstract FooFragment contributeFooFragmentInjector();
@Provides
static FooPresenter presenter() {
return new FooPresenter();
}
}
FooFragment
public class FooFragment extends Fragment implements SomeView {
@Inject FooPresenter presenter;
}
OK. At this point, and going back to
AppCompat users should continue to implement
AndroidInjector.Factory<? extends Activity>
I've had no need (and willingly opposing) to use it, only for the fragment. Do I really need to setup a module and component for it or am I missing something?
EDIT
After following EpicPandaForce's advice of using AndroidSupportInjectionModule
, Dagger now complains that
FragmentKey methods should bind
dagger.android.AndroidInjector.Factory<? extends android.app.Fragment>
, notdagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>
.