According to single responsibility and separation of concern concept no component of your application should Create the new objects of other classes it needs. Those objects(Dependencies) should be created and provided by someone else.
Dagger is (that someone else) a dependency injection framework for android and as of now, is the best amongst all. If you don’t know about Dagger and how how use it. You might find this article Tasting Dagger 2 on Android and this video useful.
What I am going to explain is how you can be more productive using Dagger2. Consider this very basic Presenter for a login screen.
public class LoginPresenter extends BasePresenter { private static final String TAG = LoginPresenter.class.getSimpleName(); public interface LoginView extends BaseView { void onLoginSuccess(); void onLoginFailure(String errorMessage); } private LoginView mLoginView; private final LoginUsecase mLoginUsecase; @Inject public LoginPresenter(LoginUsecase mLoginUsecase) { this.mLoginUsecase = mLoginUsecase; } public void login(@NonNull String username, @NonNull String password) { if (username == null || password == null) { throw new IllegalArgumentException("invalid arguments: username and password required"); } showLoading(); mLoginUsecase.login(username, password); } . . . }
We have injected the LoginUsecase dependency via dagger using @inject notation. Suppose now that we want to save user settings received in response, in Shared Preference. So lets modify our constructor:
public class LoginPresenter extends BasePresenter { private static final String TAG = LoginPresenter.class.getSimpleName(); public interface LoginView extends BaseView { void onLoginSuccess(); void onLoginFailure(String errorMessage); } private LoginView mLoginView; private final LoginUsecase mLoginUsecase; private final AppPreference appPreference; @Inject public LoginPresenter(LoginUsecase mLoginUsecase,AppPreference appPreference){ this.mLoginUsecase = mLoginUsecase; this.appPreference= appPreference; } public void login(@NonNull String username, @NonNull String password) { if (username == null || password == null) { throw new IllegalArgumentException("invalid arguments: username and password required"); } showLoading(); mLoginUsecase.login(username, password); } @Subscribe(threadMode = ThreadMode.MAIN) public void onLoginResult(LoginUsecaseImpl.EventLogin event) { hideLoading(); if (event.exception != null) { Log.d(TAG, "login failure", event.exception); } else { appPreference.setUserCode(loginResponse.getUserCode()); mLoginView.onLoginSuccess(); } } . . . }
As you can see if we were not using the Dagger we have to modify the our code on the all the locations where this Presenter’s constructor is being called. But as we are using Dagger we don’t need to do anything else other than defining the AppPreference dependency in our Dagger Module and Dagger will take care the rest!
Now if on later development stages, you need ErrorMessageFactory for custom error messages you can just inject the ErrorMessageFactory via constructor and nothing else!