📜 ⬆️ ⬇️

Dagger 2 for novice Android developers. Dagger 2. Advanced. Part 2

This article is the seventh part of a series of articles that, according to the author, are intended for those who cannot understand the implementation of dependencies and the Dagger 2 framework, or are only going to do it. The original was written on December 30, 2017. Free translation.

Dagger 2 advanced part 2 image

This is the seventh article in the series "Dagger 2 for novice Android developers." . If you have not read the previous, then you here .

Article series



Earlier in the series of articles


We looked at an example of a project and tried to get rid of strong links through dependency injection using Dagger 2 and annotations.
Also studied three new annotations. @Scope to create objects in a single copy (singleton) . @Named to separate methods that provide objects of the same type. @Qualifier as an alternative to @Named .
')

Creating Multiple Component


In the previous article, we created application level dependencies. But what if dependencies are only required for the Activity level? Activity is created and destroyed in its life cycle, and what happens to dependencies? Dependencies created inside the Activity destroyed with the Activity .

The best solution is to create separate modules and components for objects whose life cycles differ.

To explain this, I do not want to add new objects to the previously reviewed project. Instead, we will consider our MainActivity as a separate object and create our own module and component for it.

Take a look at the Dagger2Part2 branch .

Step 1. Creating an Activity Level Area


For the upcoming changes, I created a separate package called MainActivityFeature .
Create a new area (Scope) for the MainActivity .

 @Scope public @interface MainActivityScope {} 

Step 2. Create a component for MainActivity


Next, create a separate Component for the MainActivity and mark it with the annotation just created.

 @Component(dependencies = RandomUserComponent.class) @MainActivityScope public interface MainActivityComponent { RandomUserAdapter getRandomUserAdapter(); RandomUsersApi getRandomUserService(); } 

You must allow the MainActivityComponent to refer to the RandomUserComponent using the dependencies attribute. In other words, this attribute tells Dagger 2 to access the RandomUserComponent if additional dependencies are required.

In this example, at the Activity level, we need an adapter for the API and an object to create calls to the RandomUsersAPI . Therefore, we implement the getRandomUserAdapter() and getRandomUserService() methods. components connection image

Step 3. Create a module for MainActivity


Now we will create a module that will provide an adapter.

 @Module public class MainActivityModule { private final MainActivity mainActivity; public MainActivityModule(MainActivity mainActivity) { this.mainActivity = mainActivity; } @Provides @MainActivityScope public RandomUserAdapter randomUserAdapter(Picasso picasso){ return new RandomUserAdapter(mainActivity, picasso); } } 

Note: The implementation of MainActivity via an adapter is not necessary, I did this for an example. If you need a context for Picasso , then you can use holder.imageView.getContext() .

Note the @MainActivityScope annotation, which is added to the randomUserAdapter() method to limit the scope of dependency use to the Activity level.

You must also map this module to the corresponding component. We use the modules attribute.

 @Component(modules = MainActivityModule.class, dependencies = RandomUserComponent.class) @MainActivityScope public interface MainActivityComponent { RandomUserAdapter getRandomUserAdapter(); RandomUsersApi getRandomUserService(); } 

Linked all Components and Modules image

Step 4. Create an Application Class


 public class RandomUserApplication extends Application { //       private RandomUserComponent randomUserApplicationComponent; public static RandomUserApplication get(Activity activity){ return (RandomUserApplication) activity.getApplication(); } @Override public void onCreate() { super.onCreate(); Timber.plant(new Timber.DebugTree()); randomUserApplicationComponent = DaggerRandomUserComponent.builder() .contextModule(new ContextModule(this)) .build(); } public RandomUserComponent getRandomUserApplicationComponent(){ return randomUserApplicationComponent; } 

This class, inherited from Application , contains all application-level dependencies — RandomUserApplicationComponent .

Step 5. Refinement MainActivity


If you build a project, Dagger 2 will generate the DaggerMainActivityComponent class for you. To use Activity level dependencies, we need to get some application level dependencies.

 public class MainActivity extends AppCompatActivity { ... @Override protected void onCreate(Bundle savedInstanceState) { .... MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder() .mainActivityModule(new MainActivityModule(this)) .randomUserComponent(RandomUserApplication.get(this).getRandomUserApplicationComponent()) .build(); randomUsersApi = mainActivityComponent.getRandomUserService(); mAdapter = mainActivityComponent.getRandomUserAdapter(); .... } } 

Note: afterActivityLevelComponent() look at the afterActivityLevelComponent() method in the project branch.

Step 6. Congratulate yourself


We have created enough supported code. Made dependences of level of Activity . Congratulate yourself.

And what if component 50 dependencies?


If there are really many dependencies, do we need to constantly write expressions like the one below?
randomUserApi = mainActivityComponent.getRandomUserService();
mAdapter = mainActivityComponent.getRandomUserAdapter();

You may decide that this is not important for you, but there is a solution for this problem.

Using @Inject annotation


Instead of telling Dagger 2 that you need a RandomUserService and a RandomUserAdapter , let Dagger 2 handle the field, which we will mark with the @Inject annotation.

By changing the classes as below, we can start using the @Inject annotation as soon as possible. You can view the full example in the next thread .

Refinement MainActivityComponent


Remove the getRandomUserService() and getRandomUserAdapter() methods and add a method for implementing MainActivity .

 @Component(modules = MainActivityModule.class, dependencies = RandomUserComponent.class) @MainActivityScope public interface MainActivityComponent { void injectMainActivity(MainActivity mainActivity); } 

Refinement MainActivity


 public class MainActivity extends AppCompatActivity { .... @Inject RandomUsersApi randomUsersApi; @Inject RandomUserAdapter mAdapter; .... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ..... MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder() .mainActivityModule(new MainActivityModule(this)) .randomUserComponent(RandomUserApplication.get(this).getRandomUserApplicationComponent()) .build(); mainActivityComponent.injectMainActivity(this); .... } } 

How it works? When Dagger 2 finds a method without a return value ( void ), it realizes that there must be something that it needs in the class, that is, it will initialize the fields in the class that are marked with the @Inject annotation.

Exactly what is needed! Now the code can be run.
Gif
image

Summary


We looked at an example of dependency injection at the Activity level. We also saw an example of using the @Inject annotation.

Finally


Thank you for taking the time to read and support this series of articles. I hope you got some insight into dependencies and Dagger 2. The reason why I wrote this series of articles is that I improved my knowledge of Dagger 2 by reading a lot of articles in different blogs, but I gained even more knowledge while writing these articles for you. Therefore, I urge all readers to share their knowledge in any way possible. I am not an expert in Dagger 2, I consider myself only a student.

Now you can continue exploring Dagger 2 further, this series of articles should have shaped your understanding of how it works.

Links to other resources (in English)


Source: https://habr.com/ru/post/345898/


All Articles