-
Notifications
You must be signed in to change notification settings - Fork 1
Dagger2
Injecting Fragment objects | commit
-
its host Activity extends
DaggerAppCompatActivity
; -
it extends
DaggerFragment
; -
Use
@Inject
to annotate fields of this fragment that REQUIRE dependency, then delete relates code that create the fields instance; -
Use
@Inject
to annotate constructors that PROVIDE dependency, or -
Create a
@Module
annotated class, and within this class use an@Provides
annotated method to provide a dependency. -
Use
ContributesAndroidInjector
to install module to dagger graph, because the fragment must be hosted by one activity, that means the activity should also be added to dagger graph:This annotation must be applied to an abstract method in a {@link dagger.Module} that returns a concrete Android framework type (e.g. Activity, Fragment, Service, etc). The method should have no parameters.
/** * ArticleListFragment is hosted by ArticleListActivity, so we need to * install the fragment's module to this activity. */ @ContributesAndroidInjector(modules = { ArticleListActivityHostedFragment.class }) abstract ArticleListActivity bindArticleListActivity(); /** * The reason to create this class is that this activity maybe host many fragments. */ @Module abstract class ArticleListActivityHostedFragment { @ContributesAndroidInjector(modules = ArticleListFragmentModule.class) abstract ArticleListFragment bindArticleListFragment(); // another fragment ... }
- Interfaces can’t be constructed.
- Third-party classes can’t be annotated.
- Configurable objects must be configured!
Add @Inject to constructor to provide dependency, instead of defining an unnecessary @Provides annotation | commit
Because @Inject
-annotated constructor works here !
@Module
public class ArticleListFragmentModule {
ArticleListFragmentViewModel provideArticleListFragmentViewModel(ArticleListFragment fragment, ArticleListViewModelFactory factory) {
return ViewModelProviders.of(fragment, factory).get(ArticleListFragmentViewModel.class);
}
- @Provides
- ArticleListViewModelFactory provideArticleListViewModelFactory(Context context, DemoRepository repository) {
- return new ArticleListViewModelFactory(repository);
- }
}
public class ArticleListViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private final DemoRepository mRepository;
+ @Inject
public ArticleListViewModelFactory(DemoRepository repository) {
mRepository = repository;
}
simplify
public class ArticleListViewModelFactory extends ViewModelProvider.NewInstanceFactory {
- private final DemoRepository mRepository;
+ @Inject
+ DemoRepository mRepository;
@Inject
- public ArticleListViewModelFactory(DemoRepository repository) {
- mRepository = repository;
+ public ArticleListViewModelFactory() {
}
This is another good code snippet to show the advantage of dagger. With dagger, we can simplify the constructor to a default one without any parameters. The fields which need to be initialized in constructor, just @Inject
it. If we need to provide a singleton instance, just @Singleton
it, instead of using a static
filed to hold the instance.
One of three types of dependency injection, WIKI- Constructor injection: This method requires the client to provide a parameter in a constructor for the dependency.
A class contains constructors that are invoked to create objects from the class blueprint. Java Doc - Providing Constructors for Your Classes
@Singleton
public class DemoRepository {
- private static final Object LOCK = new Object();
- private static DemoRepository sInstance;
- private final ArticleDao mArticleDao;
- private final DemoWebService mDemoWebService;
- private final AppExecutors mExecutors;
- private final Context mContext;
+ @Inject
+ ArticleDao mArticleDao;
+ @Inject
+ DemoWebService mDemoWebService;
+ @Inject
+ AppExecutors mExecutors;
+ @Inject
+ Context mContext;
+
private RateLimiter<String> repoListRateLimit = new RateLimiter<>(2, TimeUnit.MINUTES);
- public DemoRepository(
- Context context, ArticleDao articleDao, DemoWebService demoWebService, AppExecutors executors) {
- mContext = context;
- mArticleDao = articleDao;
- mDemoWebService = demoWebService;
- mExecutors = executors;
- }
-
- public synchronized static DemoRepository getInstance(
- Context context, ArticleDao articleDao, DemoWebService demoWebService, AppExecutors executors) {
- Log.d(LOG_TAG, "Getting the repository");
- if (sInstance == null) {
- synchronized (LOCK) {
- if (sInstance == null) {
- sInstance = new DemoRepository(context, articleDao, demoWebService, executors);
- Log.d(LOG_TAG, "Made new repository");
- }
- }
- }
- return sInstance;
+ @Inject
+ public DemoRepository(){
}
Provide dependency for Configurable objects must be configured! | commit
But sometimes the object need to be configured, for example, it needs exactly integer instead of another instance:
public class DemoRepository {
- private RateLimiter<String> repoListRateLimit = new RateLimiter<>(2, TimeUnit.MINUTES);
+ @Inject
+ RateLimiter<String> repoListRateLimit;
}
public class AppModule {
+ @Provides
+ RateLimiter<String> provideRateLimiter() {
+ return new RateLimiter<>(2, TimeUnit.MINUTES);
+ }
}
Consider Dependency Inject whenever you want to use keyword new
| commit
cannot be provided without an @Inject constructor or from an @Provides-annotated method.
The following 3 articles introduce how to use Dagger2 in a real Android App Project.
In part1, to attach activities/fragments to dagger graph, it create a lot boilerplate classes and needs a lot repetitive tasks, so is too complicated, so just walk through part1.
In part2, use @ContributesAndroidInjector
to simplify dagger graph, check this commit for details
In part3, use DaggerActivity
, DaggerFragment
, DaggerApplication
to reduce boilerplate in your Activity/Fragment/Application, use AndroidInjector<T>
in your dagger components to reduce boilerplate too.