In the previous article, we looked at how we can use the special dagger-android module to provide dependencies to activations and fragments, as well as organizing different scopes.
In this article we will look at the components of the module, consider the provision of dependencies to other basic components of the android, and also consider options for providing dependencies with dynamic parameters.
The dagger-android module allows you to inject dependencies into the following basic android components:
Activity, Fragment, Service, DaggerIntentService, BroadcastReceiver, ContentProvider.
If we use classes from the support library (for example, AppCompatActivity, android.support.v4.app.Fragment
), then we need to use the corresponding classes from the additional dagger support library (dagger-android-support).
It serves to inject dependencies into the heirs of the basic components ( Activity, Fragment, ..
).
@ContributesAndroidInjector
This annotation should be applied over the abstract method in the module, where the returned type of the method is the heir to the base component of the android ( Activity, Fragment ..
). The method should not have parameters.
This annotation serves to generate the AndroidInjector
for the return type of method above which the annotation is indicated. This AndroidInjector
is a subcomponent. This subcomponent is a child of the component (or subcomponent) to which this module (in which this annotation is present) will be added.
The annotation contains the modules
parameter. This parameter indicates which modules will be added to this generated subcomponent.
Above the annotated @ContributesAndroidInjector
there may also be an annotation of scopa. This scop will be applied to the generated subcomponent.
Built-in dagger-android library module. Must be added to root component.
Contains multibindig collections with factories to create subcomponents that were generated using the @ContributesAndroidInjector
annotation. For each basic component of the android has its own collection.
Is a proxy AndroidInector
, contains a collection of factories for creating a subcomponent ( AndroidInjector
) for a particular type. For example, DispatchingAndroidInjector<Activity>
contains all subcomponent creation factories for the heirs of the Activity
. On injection, it searches for the necessary factory, creates a subcomponent ( AndroidInject
) and injects dependencies.
The utility class has an overloaded inject
method for all base types ( Activity, Fragment, Service ..
). Depending on the type transferred, it is looking for an implementation of one of the following interfaces:
dagger-android-support
The search for the implementation of the desired interface containing the desired AndroidInject
occurs for an object whose lifetime is higher.
Interfaces HasActivityInjector, HasServiceInjector, HasContentProviderInjector, HasBroadcastReceiverInjector
should be implemented in the application. The HasFragmentInjector
or HasSupportFragmentInjector
can be implemented in a fragment or activation or in an application
, the implementation is searched in the following order: the parent fragment, the activation in which this fragment is located and application
.
AndroidInjection.inject()
must be called in a specific method before calling the super method:
Dagger-android has classes that we can use (these classes already implement the necessary interfaces and the call to the AndroidInjection.inject()
method):
dagger-android-support
If for some reason we cannot extend one of these classes, then we can always implement the necessary interface.
We define our main component:
Our component must inherit AndroidInjector
, because when using the DaggerApplication
we will need to implement one method that should return AndroidInjector
. This is only necessary to do for the application
, because we manually define the main component.
@Component(modules = {AppModule.class, AndroidSupportInjectionModule.class}) @Singleton public interface AppComponent extends AndroidInjector<App> { @Component.Builder abstract class Builder extends AndroidInjector.Builder<App> {} }
Define the main module
In this module, we will add a "mapping" for our activation, service, and Broadcast receiver. Sub-components will be generated for them and will be added to the main component, since we connected this module to the main component.
@Module abstract public class AppModule { @Provides @Singleton public static Context context(App app) { return app.getApplicationContext(); } @Provides @Singleton public static UserRepository userRepository(Context context) { return new UserRepositoryImpl(context); } @ContributesAndroidInjector(modules = { ActivityModule.class }) @ActivityScope abstract MainActivity mainActivity(); @ContributesAndroidInjector(modules = { ServiceModule.class }) @ServiceScope abstract MyIntentService myIntentService(); @ContributesAndroidInjector @ReceiverScope abstract SomeReceiver connectionReceiver(); }
Define our Application class
public class App extends DaggerApplication { @Override protected AndroidInjector<? extends DaggerApplication> applicationInjector() { return DaggerAppComponent.builder().create(this); } }
Activity Example
public class MainActivity extends DaggerAppCompatActivity { @Inject UserRepository userRepository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //userRepository } }
Example with IntentService
public class MyIntentService extends DaggerIntentService { @Inject UserRepository userRepository; public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(@Nullable Intent intent) { //userRepository } }
Receiver example
public class SomeReceiver extends DaggerBroadcastReceiver { @Inject UserRepository userRepository; @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); //userRepository } }
When using dagger-android, components and subcomponents live for the life of the android components ( Activity, Fragment, Service
, etc.) in which they were created and they are not necessary to manually decompose. For example, the activation subwoofer is created at the time of the call to AndroidInjection.inject()
and lives until the activation is destroyed.
With the use of dagger-android, we do not need to build subcomponents and the dependency request is now reached by a single call to AndroidInjection.inject()
, and using ready-made classes from the dagger library (for example, DaggerAppCompatActivity
), we can immediately use dependencies. A question may arise, how can we do this:
long userId = getArguments().getLong(USER_ID); getAppComponent() .plusUserComponent(new UserModule(userId)) .inject(this);
userId is a dynamic parameter for a module. For example, this parameter can be used to create a UserPresenter(UserRepository userRepository, Long userId)
.
Implementation options:
Option 1:
Setting parameters to the object where it is used.
public class UserPresenter { private UserView userView; private UserRepository userRepository; private long userId; @Inject public UserPresenter(UserView userView, UserRepository userRepository) { this.userView = userView; this.userRepository = userRepository; } public void setUserId(long userId) { this.userId = userId; } } public class UserFragment extends BaseFragment implements UserView { @Inject UserPresenter userPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); userPresenter.setUserId(userId); } }
This option is not suitable for immutable classes.
Option 2:
Rebuild the class itself so that it does not accept dynamic parameters during creation, and use the parameter itself through methods:
public final class UserPresenter { private final UserView userView; private final UserRepository userRepository; @Inject public UserPresenter(final UserView userView, final UserRepository userRepository) { this.userView = userView; this.userRepository = userRepository; } public void loadUserInfo(long userId) { // } } public class UserFragment extends BaseFragment implements UserView { @Inject UserPresenter userPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); userPresenter.loadUserInfo(userId); } }
Option 3:
Implement the creation of an object with dynamic parameters using the factory:
public final class UserPresenter { private final UserView userView; private final UserRepository userRepository; private final long userId; public UserPresenter(final UserView userView, final UserRepository userRepository, long userId) { this.userView = userView; this.userRepository = userRepository; this.userId = userId; } } public final class UserPresenterFactory { private final UserView userView; private final UserRepository userRepository; @Inject public UserPresenterFactory(UserView userView, UserRepository userRepository) { this.userView = userView; this.userRepository = userRepository; } public UserPresenter create(long userId) { return new UserPresenter(userView, userRepository, userId); } } public class UserFragment extends BaseFragment implements UserView { @Inject UserPresenterFactory userPresenterFactory; UserPresenter userPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); userPresenter = userPresenterFactory.create(userId); } }
Writing such factories may not be convenient or take some time; for solving this problem, you can look towards AutoFactory .
There is a solution from Fernando Cejas, more suitable for those who use RxJava:
Dynamic Parameters in Use Cases
Dagger-android allows you to provide dependencies to the basic components of the android ( activity, fragment, service
, etc.) in a more convenient way, it saves us from creating subcomponents and controlling them. Activations, fragments, services, etc. look more “clean”.
I hope this article has helped you more to understand the possibilities of dagger-android.
Source: https://habr.com/ru/post/336462/
All Articles