how it works #BindsInstance dagger 2 - dagger-2

I have recently updated dagger 2.8 to 2.9 dagger. and documentation of the last release have been added as follows:
-Added #BindsInstance for component builders to easily bind instances that are constructed outside of the graph.
-Producers: Added ProducerMonitor.ready (), which is called when all of a producer's inputs are available.
-Removed #Provides(type =...) usage. Use the annotations in dagger.multibindings instead. #Produces.type was also removed.
-All binding methods are now validated, even if they are unused in a particular #Component
-#Component.dependencies can no longer include #Modules.
I want to know how these new features:
Thank you!!
Note: I am new to dagger 2, but you want to be able to make maximum use of this library.

#bindsInstance is used for removing constructor from module and chaining modules where you get component.
Without #BindsInstance
#Module
public class AppModule {
private final Application application;
public AppModule(Application application) {
this.application = application;
}
#Provides
#Singleton
Application provideApplication() {
return application;
}
#Provides
#Singleton
public SharedPreferences providePreferences() {
return application.getSharedPreferences("store",
Context.MODE_PRIVATE);
}
}
These modules(ToastMakerModule, and SensorControllerModule) are for learning purposes they get context and instantiate , may not be practical for real examples
public class ToastMaker {
private Application application;
public ToastMaker(Application application) {
this.application = application;
}
public void showToast(String message) {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
}
}
#Module
public class ToastMakerModule {
#Singleton
#Provides
ToastMaker provideToastMaker(Application application) {
return new ToastMaker(application);
}
}
#Singleton
#Component(modules = {AppModule.class, ToastMakerModule.class, SensorControllerModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
// DaggerAppComponent.build() returns this Builder interface
#Component.Builder
interface Builder {
AppComponent build();
Builder appModule(AppModule appModule);
Builder sensorControllerModule(SensorControllerModule sensorControllerModule);
Builder toastMakerModule(ToastMakerModule toastMakerModule);
}
}
Build component like this
appComponent = DaggerAppComponent
.builder()
.appModule(new AppModule(this))
.sensorControllerModule(new SensorControllerModule())
.toastMakerModule(new ToastMakerModule())
.build();
With #BindsInstance
#Module
public class AppModule {
#Provides
#Singleton
public SharedPreferences providePreferences(Application application) {
return application.getSharedPreferences("data",
Context.MODE_PRIVATE);
}
}
Component
#Singleton
#Component(modules = {AppModule.class, ToastMakerModule.class, SensorControllerModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
#Component.Builder
interface Builder {
AppComponent build();
// #BindsInstance replaces Builder appModule(AppModule appModule)
// And removes Constructor with Application AppModule(Application)
#BindsInstance
Builder application(Application application);
}
}
and build component like this
appComponent = DaggerAppComponent
.builder()
.application(this)
.build();

#BindsInstance lets the component host the dependency directly and hence the lifetime is the lifetime of the component. This can be used to avoid #Singleton scope. Does it even matter? Avoiding singleton scope helps DaggerAppComponent access the provider without a costly DoubleCheck. So yes, it is possible to still use the module and not use any scopes. However, using module still means that DaggerAppComponent is going to use a Provider factory to inject the dependency. Using #BindsInstance, the provider is not needed at all unless the dependency is injected lazily via Lazy<> or Provider<>.
Any dependencies (like String constants etc) that is known as AppComponent is being created are good candidates for #BindsInstance. Note this is based on Dagger 2.19.

Related

Dagger2: wildcard with Generics

I'm new to Dagger2 and DI in general, but I'm interested to populate a map with injected keys/values. The problem is that it works if I provide the exact types, I can't make it work with wildcards, any solution for that?
#Module
public class SimpleIssueModule
{
#Provides
#Singleton
#IntoMap
#StringKey("simple_issue")
public SimpleIssue provideSimpleIssue()
{
return new SimpleIssue();
}
}
#Module
public class DaggerFactoryModule
{
#Provides
#Singleton
public Factory provideFactory(Map<String, Provider< ? extends Issue>> map)
{
return new Factory(map);
}
}
If you want a map of Provider< ? extends Issue>> map, then you need to use Issue as the type returned in your module. Dagger will not do any casting or guessing on its own.
#Provides
#Singleton
#IntoMap
#StringKey("simple_issue")
public Issue provideSimpleIssue() {
return new SimpleIssue();
}
what to do in case I need a Module that provides a base class (Issue) into a Map and also need a provider of the concrete class (SimpleIssue) and I would like it to be Singleton (same instance returns in both cases)
In this case you provide the #Singleton of SimpleIssue.
#Provides
#Singleton
public SimpleIssue provideSimpleIssue() {
return new SimpleIssue();
}
// or you can use constructor injection, dropping the method above...
#Singleton
public class SimpleIssue {
#Inject
public SimpleIssue(...) {
}
}
Then you bind this instance into a Map. There is no need for a scope, since the implementation should declare it (as done above).
#Provides
#IntoMap
#StringKey("simple_issue")
public Issue provideSimpleIssue(SimpleIssue issue) {
return issue;
}
// or alternatively with `#Binds` when using an abstract class / interface
// this leads to actually better performing dagger code
#Binds
#IntoMap
#StringKey("simple_issue")
public Issue provideSimpleIssue(SimpleIssue issue);

Android How to add external dependency (context) to SubComponent builder in Dagger 2.1.0

I am using dependency injection according to google sample
The only external dependency I can pass is through AppComponent builder
#Singleton
#Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
MainTabActivityModule.class,
CoreActivityModule.class
})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MyApplication myApplication);
}
and injected in app like this
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent
.builder()
.application(myApplication)
.build().inject(myApplication);
...
}
According to document injecting in Activity looks like this. I added what I would like to achieve.
public class YourActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
AndroidInjection
//.builder() THIS IS WHAT I WANT TO ACHIEVE
//.addActivityContext(this) THIS IS WHAT I WANT TO ACHIEVE
//.build() THIS IS WHAT I WANT TO ACHIEVE
.inject(this);
super.onCreate(savedInstanceState);
}
}
but the question is how can I add additional parameter to subComponent.
#Subcomponent
public interface CoreActivitySubComponent extends AndroidInjector<CoreAppActivity> {
// #Subcomponent.Builder
// interface Builder {
// Builder addContext(Context context) //did not work
// CoreActivitySubComponent build(); //did not work
// }
//==or using abstract class
// in this option I do not know where to add parameter to this builder
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<CoreAppActivity> {
}
}
Did you add the ContextModule to your #Subcomponent similar to this answer?
I think your #Subcomponent should look something like this:
#Subcomponent(module = {ContextModule.class})
interface MainTabActivityComponent extends AndroidInjector<CoreAppActivity> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<CoreAppActivity> {
abstract Builder addContextModule(ContextModule contextModule);
#Override
public void seedInstance(CoreAppActivity instance) {
addContextModule(new ContextModule(instance));
}
}
}
And finally don't forget to include this #Subcomponent in your binding-module.
One last question: is this really required?
I found that using the AndroidInjector on the Application as well as Activities and Fragments will give me the correct corresponding Context when I inject it.
The problem was that Dagger 2.1.0 method AndroidInjection.inject(this); which is supposed to be used in Activity and Fragment, do not provide any builder to add external dependency.
I wanted to create general module which depends on Activity/Fragment context.
sample:
public class ToastController {
private Context context;
#Inject
public ToastController(Context context) {
this.context = context;
}
public void showToast(#StringRes int res) {
Toast.makeText(context, context.getText(res), Toast.LENGTH_SHORT).show();;
}
}
But I was not able to generalize it to the level, that I could provide just one context modude, instead I had to do create binds module for every single Activity/ Fragment that uses this module.
#Singleton
#Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
MainTabActivityModule.class,// IMPORTANT CLASS
})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MyApplication myApplication);
}
This is a place, where I provide context module for each Activity
#Module
public abstract class MainTabActivityModule
#ContributesAndroidInjector(modules = ContextMainTabActivityModule.class)//THIS MODULE
abstract MainTabActivity contributeMainActivity();
}
and Context is provided using #Binds annotation
#Module
public abstract class ContextMainTabActivityModule {
#Binds
abstract Context provideContext(MainTabActivity featureActivity);
}
=====================
It can be done by overriding method seedInstance according to sample
I tried this, but it did not work for me
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<CoreAppActivity> {
abstract Builder addContextModule(ContextModule contextModule);
#Override
public void seedInstance(CoreAppActivity instance) {
addContextModule(new ContextModule(instance));
}
}
next class
#Module
public class ContextModule {
private CoreAppActivity coreAppActivity;
#Provides
Context getContext() {
return coreAppActivity.getBaseContext();
}
public ContextModule(CoreAppActivity coreAppActivity) {
this.coreAppActivity = coreAppActivity;
}
}

Dagger 2.11 ContributesAndroidInjector Singleton dependency injection fails

I am exploring the new dagger.android from Dagger 2.11. I hope not to have to create custom scope annotation like #PerActivity. So far I was able to do the following:
1) Define Application scope Singletons and injecting them into activities.
2) Define Activity scope non-Singleton dependencies and injecting them into their activities using #ContributesAndroidInjector
What I cannot figure out is how to have an Application scope Singleton and Activity scope non-Singletons using it.
In the example below, I would like my Activity scope MyActivityDependencyA and MyActivityDependencyB to have access to a Singleton MyActivityService
The setup below results in:
Error:(24, 3) error: com.example.di.BuildersModule_BindMyActivity.MyActivitySubcomponent
(unscoped) may not reference scoped bindings:
#Singleton #Provides com.example.MyActivityService
com.example.MyActivitySingletonsModule.provideMyActivityService()
Here is my setup. Note, I defined separate MyActivitySingletonsModule and MyActivityModule since I could not mix Singleton and non-Singleton dependencies in the same Module file.
#Module
public abstract class BuildersModule {
#ContributesAndroidInjector(modules = {MyActivitySingletonsModule.class, MyActivityModule.class})
abstract MyActivity bindMyActivity();
}
}
and
#Module
public abstract class MyActivityModule {
#Provides
MyActivityDependencyA provideMyActivityDependencyA(MyActivityService myActivityService){
return new MyActivityDependencyA(myActivityService);
}
#Provides
MyActivityDependencyB provideMyActivityDependencyB(MyActivityService myActivityService) {
return new MyActivityDependencyB(myActivityService);
}
}
and
#Module
public abstract class MyActivitySingletonsModule {
#Singleton
#Provides
MyActivityService provideMyActivityService() {
return new MyActivityService();
}
}
and
#Singleton
#Component(modules = {
AndroidSupportInjectionModule.class,
AppModule.class,
BuildersModule.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(App application);
AppComponent build();
}
void inject(App app);
}
Is it even possible to do what I am trying to do without defining custom scope annotations?
Thanks in advance!
Why avoid custom scopes? Custom scopes are still required for the new dagger.android dependency injection framework introduced in Dagger 2.10+.
"My understanding is #ContributesAndroidInjector removes the need for custom annotation and I was able to prove it by using non-singletons defined in the activity scope without any issues."
#ContributesAndroidInjector (available in v2.11) does not remove the need for custom scopes. It merely replaces the need to declare #Subcomponent classes that does not make use of #Subcomponent.Builder to inject dependencies required by the component at runtime. Take a look at the below snippet from the official dagger.android user guide about #ContributesAndroidInjector;
"Pro-tip: If your subcomponent and its builder have no other methods or supertypes than the ones mentioned in step #2, you can use #ContributesAndroidInjector to generate them for you. Instead of steps 2 and 3, add an abstract module method that returns your activity, annotate it with #ContributesAndroidInjector, and specify the modules you want to install into the subcomponent. If the subcomponent needs scopes, apply the scope annotations to the method as well."
#ActivityScope
#ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
The key here is "If the subcomponent needs scopes, apply the scope annotations to the method as well."
Take a look at the following code for an overview of how to use #Singleton, #PerActivity, #PerFragment, and #PerChildFragment custom scopes with the new dagger.android injection framework.
// Could also extend DaggerApplication instead of implementing HasActivityInjector
// App.java
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);
}
// Could also extend DaggerActivity instead of implementing HasFragmentInjector
// MainActivity.java
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;
}
}
// MainActivityModule.java
#Module
public abstract class MainActivityModule {
#PerFragment
#ContributesAndroidInjector(modules = MainFragmentModule.class)
abstract MainFragment mainFragmentInjector();
}
// Could also extend DaggerFragment instead of implementing HasFragmentInjector
// MainFragment.java
public final class MainFragment extends Fragment implements HasFragmentInjector {
#Inject
AppDependency appDependency; // same object from App
#Inject
ActivityDependency activityDependency; // same object from MainActivity
#Inject
FragmentDependency fragmentDepency;
#Inject
DispatchingAndroidInjector<Fragment> childFragmentInjector;
#SuppressWarnings("deprecation")
#Override
public void onAttach(Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Perform injection here before M, L (API 22) and below because onAttach(Context)
// is not yet available at L.
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;
}
}
// 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 fragmentDepency; // same object from MainFragment
#Inject
ChildFragmentDependency childFragmentDepency;
#Override
public void onAttach(Context context) {
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() {
}
}
For a complete dagger.android 2.11 setup guide using #ContributesAndroidInjector and custom scopes mentioned above, read this article.
There are some problems here: firstly, ActivitySingleton doesn't make much sense. A dependency is either a singleton (per app, or app scoped) or not.
If it is not a singleton it could be activity scoped (per activity). This would mean it lived and died with the Activity i.e., that its lifecycle was congruent with that of the Activity itself and hence it would be destroyed with the onDestroy of the Activity.
That doesn't mean that everything that is injected inside an Activity must be #PerActivity. You can still inject #Singleton dependencies there (like per app OkHttpClient for instance). However, these #Singleton dependencies will not be bound in the module set that composes a #PerActivity component. Instead, they will be bound in the module set for parent components and obtained through the component hierarchy (dependent components or sub-components).
These means that your ActivitySingletonsModule is incorrect, see the comments in the code below:
#Module
public abstract class MyActivitySingletonsModule {
//#Singleton
//^^ remove the annotation here if you want to use the
//in your ActivityComponent
//If you need this as a per-app singleton, then include
//this module at the AppComponent level
#Provides
MyActivityService provideMyActivityService() {
return new MyActivityService();
}
}
I do not understand the reluctance to define a custom scope. These are extremely lightweight and can improve readability. Here is the single line of code you would need to create a #PerActivity scope.
#Scope #Retention(RetentionPolicy.RUNTIME) public #interface PerActivity {}
I suspect the concept of scopes is unclear and this is leading to the reluctance. Admittedly, it can be rather confusing. However there are some really good canonical answers that help clarify. I would suggest this question as a start:
Dagger2 Custom Scopes : How do custom-scopes (#ActivityScope) actually work?

About Dagger 2. Connection of #inject and #provide

If there is #inject, then it means there must be #provide?
inject field gets its value from #provide method of module?
Yes if you use Module
#Module
public class SomeModule {
#Provides
Unscoped unscoped() {
return new Unscoped();
}
#Provides
#Singleton
Scoped scoped() {
return Scoped();
}
}
BUT classes with #Inject constructor get automatically appended to your scoped component even if no module is specified for it:
#Singleton
public class Scoped {
#Inject
public Scoped() {
}
}
public class Unscoped {
#Inject
public Unscoped() {
}
}
If there is #Inject annotation then it's dependency can be provided in two ways :
By Using Provides annotation in module
#Provides
TasksPresenter provide TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
return new TasksPresenter(tasksRepository,tasksView);
}
By Using Constructor Injection
#Inject
TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
mTasksRepository = tasksRepository;
mTasksView = tasksView;
}
One thing to observe here is Constructor Injection solve two thing
Instantiate object
Provides the object by adding it to Object graph.

Dagger 2 Activity context/ApplicationContext modules

I'm struggling with dagger 2 in order to understand how i can pass a context or another according to my needs.
- First I have an ApplicationModule annotated #Singleton since it provides hi level objects like the webservice object, the model ..., generally those objects are passed the ApplicationContext (since the y need to live during the whole Application lifetime)
#Singleton
#dagger.Component(modules = {
AppModule.class
})
public interface AppComponent {
void inject(MyApp application);
Model model();
Context context();<--- should provide the application Context for the Object above (model)
...
the implementation looks like that
#dagger.Module
public class AppModule {
private final Application app;
public ApplModule(Application app) {
this.app = app;
}
#Provides
#Singleton
Model provideModel(Bus bus) {
return new Model(bus);
}
#Provides
#Singleton
Context provideApplicationContext() {
return app.getApplicationContext();
}
...
secondly I have an Activity Scope componenet in with I provide the current activity and different views which need a Context.
#ActivityScope
#Component(
dependencies = AppComponent.class
, modules = {ActivityModule.class}
)
public interface ActivityComponent {
void inject(MyActivity activity);
Context context(); <---should provide the activity's context
MyView homeView(); <----takes a Context as a contructor parameter
#Module
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
#Provides
#ActivityScope
public Activity activity() {
return activity;
}
#Provides
#ActivityScope
#Named("viewcontext") <----- if I removed this I get an error from Dagger
public Context context() {
return activity;
}
#Provides
#ActivityScope
MyView provideZeView(Bus bus, Model model) { <---- previously receiving the ApplicationContext as a parameter
MyView v = new MyView(activity, bus, model); <---- must pass the activity otherwise passing the Context reveived is the ApplicationContext
return v;
}
so Here are my questions:
I used scopes in order to have a better "granularity" over what is passed and i still get the applicationContext
If I remove the #Named qulifier i get an error
previously the Views where produced by another module with a dependence to the ActivityModule but still getting the ApplicationContext
Well the point is I am certainly missing something...but I can't figure what, maybe I misundestood the use of Scopes
you can use qualifiers like this. in two separate files define the following:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityContext {
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationContext {
}
then in your ActivityModule do this:
#Provides
#ActivityScope
#ActivityContext
public Context context() {
return activity;
}
and likewise in your appmodule do this:
#Provides
#Singleton
#ApplicationContext
Context provideApplicationContext() {
return app.getApplicationContext();
}
now we have a way to ask for whatever type of context we need based on the qualifier #ApplicationContext and #ActivityContext.
so for example in your activity you could do this:
#Inject #ApplicationContext
Context c;
which would inject an application context.
and in a module you could do this for example:
#Provides
#ActivityScope
LoginPresenter provideLoginPresenter(#ActivityContext Context context) {
return new LoginPresenter(context);
}
to provide an activity context. this is just an example.
#Named is a requirement if you want to provide multiple objects of the same type from your module.
As far as your second question, in regards to passing the correct Activity context, you need to have this in your ActivityComponent:
Activity activity();