-
-
Save vestrel00/64be913f954989fe52c674247e093218 to your computer and use it in GitHub Desktop.
// This is a super simplified example of how to use the new dagger.android framework | |
// introduced in Dagger 2.10. For a more complete, in-depth guide to dagger.android | |
// read https://proandroiddev.com/how-to-android-dagger-2-10-2-11-butterknife-mvp-part-1-eb0f6b970fd | |
// For a complete codebase using dagger.android 2.11-2.17, butterknife 8.7-8.8, and MVP, | |
// see https://github.com/vestrel00/android-dagger-butterknife-mvp | |
// This example works with Dagger 2.11-2.17. Starting with Dagger 2.11, | |
// @ContributesAndroidInjector was introduced removing the need to define @Subcomponent classes. | |
// App.java | |
// Could also extend DaggerApplication instead of implementing HasActivityInjector | |
public class App extends Application implements HasActivityInjector { | |
@Inject | |
AppDependency appDependency; | |
@Inject | |
DispatchingAndroidInjector<Activity> activityInjector; | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
DaggerAppComponent.create().inject(this); | |
} | |
@Override | |
public AndroidInjector<Activity> activityInjector() { | |
return activityInjector; | |
} | |
} | |
// AppModule.java | |
@Module(includes = AndroidInjectionModule.class) | |
abstract class AppModule { | |
@PerActivity | |
@ContributesAndroidInjector(modules = MainActivityModule.class) | |
abstract MainActivity mainActivityInjector(); | |
} | |
// AppComponent.java | |
@Singleton | |
@Component(modules = AppModule.class) | |
interface AppComponent { | |
void inject(App app); | |
} | |
// MainActivity.java | |
// Could also extend DaggerActivity instead of implementing HasFragmentInjector | |
public final class MainActivity extends Activity implements HasFragmentInjector { | |
@Inject | |
AppDependency appDependency; // same object from App | |
@Inject | |
ActivityDependency activityDependency; | |
@Inject | |
DispatchingAndroidInjector<Fragment> fragmentInjector; | |
@Override | |
protected void onCreate(@Nullable Bundle savedInstanceState) { | |
AndroidInjection.inject(this); | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.main_activity); | |
if (savedInstanceState == null) { | |
addFragment(R.id.fragment_container, new MainFragment()); | |
} | |
} | |
@Override | |
public final AndroidInjector<Fragment> fragmentInjector() { | |
return fragmentInjector; | |
} | |
private final void addFragment(@IdRes int containerViewId, Fragment fragment) { | |
getFragmentManager.beginTransaction() | |
.add(containerViewId, fragment) | |
.commit(); | |
} | |
} | |
// MainActivityModule.java | |
@Module | |
public abstract class MainActivityModule { | |
@PerFragment | |
@ContributesAndroidInjector(modules = MainFragmentModule.class) | |
abstract MainFragment mainFragmentInjector(); | |
} | |
// MainFragment.java | |
// Could also extend DaggerFragment instead of implementing HasFragmentInjector | |
// Could instead extend DialogFragment to add DialogFragment capabilities. | |
// DialogFragments may be embedded as regular fragments in a view of an Activity or Fragment | |
// and may also be shown as a dialog or in an alert dialog. | |
public final class MainFragment extends Fragment implements HasFragmentInjector { | |
@Inject | |
AppDependency appDependency; // same object from App | |
@Inject | |
ActivityDependency activityDependency; // same object from MainActivity | |
@Inject | |
FragmentDependency fragmentDependency; | |
@Inject | |
DispatchingAndroidInjector<Fragment> childFragmentInjector; | |
@SuppressWarnings("deprecation") | |
@Override | |
public void onAttach(Activity activity) { | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | |
// Perform injection here for versions before M as onAttach(*Context*) did not yet exist | |
// This fixes DaggerFragment issue: https://github.com/google/dagger/issues/777 | |
AndroidInjection.inject(this); | |
} | |
super.onAttach(activity); | |
} | |
@Override | |
public void onAttach(Context context) { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | |
// Perform injection here for M (API 23) due to deprecation of onAttach(*Activity*). | |
AndroidInjection.inject(this); | |
} | |
super.onAttach(context); | |
} | |
@Override | |
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, | |
Bundle savedInstanceState) { | |
return inflater.inflate(R.layout.main_fragment, container, false); | |
} | |
@Override | |
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { | |
super.onViewCreated(view, savedInstanceState); | |
if (savedInstanceState == null) { | |
addChildFragment(R.id.child_fragment_container, new MainChildFragment()); | |
} | |
} | |
@Override | |
public final AndroidInjector<Fragment> fragmentInjector() { | |
return childFragmentInjector; | |
} | |
private final void addChildFragment(@IdRes int viewId, Fragment fragment) { | |
getChildFragmentManager() | |
.beginTransaction() | |
.add(viewId, fragment) | |
.commit(); | |
} | |
} | |
// MainFragmentModule.java | |
@Module | |
public abstract class MainFragmentModule { | |
@PerChildFragment | |
@ContributesAndroidInjector(modules = MainChildFragmentModule.class) | |
abstract MainChildFragment mainChildFragmentInjector(); | |
} | |
// MainChildFragment.java | |
public final class MainChildFragment extends Fragment { | |
@Inject | |
AppDependency appDependency; // same object from App | |
@Inject | |
ActivityDependency activityDependency; // same object from MainActivity | |
@Inject | |
FragmentDependency fragmentDependency; // same object from MainFragment | |
@Inject | |
ChildFragmentDependency childFragmentDependency; | |
@SuppressWarnings("deprecation") | |
@Override | |
public void onAttach(Activity activity) { | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | |
// Perform injection here for versions before M as onAttach(*Context*) did not yet exist | |
// This fixes DaggerFragment issue: https://github.com/google/dagger/issues/777 | |
AndroidInjection.inject(this); | |
} | |
super.onAttach(activity); | |
} | |
@Override | |
public void onAttach(Context context) { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | |
// Perform injection here for M (API 23) due to deprecation of onAttach(*Activity*). | |
AndroidInjection.inject(this); | |
} | |
super.onAttach(context); | |
} | |
@Override | |
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, | |
Bundle savedInstanceState) { | |
return inflater.inflate(R.layout.main_child_fragment, container, false); | |
} | |
} | |
// MainChildFragmentModule.java | |
@Module | |
public abstract class MainChildFragmentModule { | |
} | |
// PerActivity.java | |
@Scope | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface PerActivity { | |
} | |
// PerFragment.java | |
@Scope | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface PerFragment { | |
} | |
// PerChildFragment.java | |
@Scope | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface PerChildFragment { | |
} | |
// AppDependency.java | |
@Singleton | |
public final class AppDependency { | |
@Inject | |
AppDependency() { | |
} | |
} | |
// ActivityDependency.java | |
@PerActivity | |
public final class ActivityDependency { | |
@Inject | |
ActivityDependency() { | |
} | |
} | |
// FragmentDependency.java | |
@PerFragment | |
public final class FragmentDependency { | |
@Inject | |
FragmentDependency() { | |
} | |
} | |
// ChildFragmentDependency.java | |
@PerChildFragment | |
public final class ChildFragmentDependency { | |
@Inject | |
ChildFragmentDependency() { | |
} | |
} |
Here is my response to that: google/dagger#899 (comment)
This isn't working. I copied this gist letter for letter and I'm getting error No injector factory bound for Class MainChildFragment
Hey there @ezamelczyk! I just saw your comment about the error you are getting. I was able to reproduce the error. The error is caused by code that is not shown in this gist, which is MainFragment#addChildFragment(int viewId, Fragment fragment)
.
You need to make sure that you use the childFragmentManager
like so;
class MainFragment {
void addChildFragment(int viewId, Fragment fragment) {
getChildFragmentManager()
.beginTransaction()
.add(viewId, fragment)
.commit();
}
}
The error you are getting is due to the use of the regular fragment manager;
class MainFragment {
void addChildFragment(int viewId, Fragment fragment) {
getFragmentManager()
.beginTransaction()
.add(viewId, fragment)
.commit();
}
}
To prevent this pitfall, I'll update the gist and include this missing code. Thanks!
Adopted it with DaggerApplication in this fork which simplifies things even more but differs noticeably on these two,
public class App extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder().create(this);
}
}
@Singleton
@Component(modules = {AndroidSupportInjectionModule.class, AppModule.class})
public interface AppComponent extends AndroidInjector<MainApplication> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MainApplication> {
}
}
Thank you for the example.
I tried to implement the same approach in my project but am having an issue. : google/dagger#899
Can you check it out ?