Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building modular architecture apps with Dagger 2

Building modular architecture apps with Dagger 2

Dagger 2 is Google's library that allow manage project dependencies effectively. In the talk we will look into modular architecture concept and implementation using MVP and Dagger 2.

Kseniia Shumelchyk

September 09, 2016
Tweet

More Decks by Kseniia Shumelchyk

Other Decks in Programming

Transcript

  1. Building modular architecture apps with Dagger 2 Kseniia Shumelchyk Software

    Engineer @ Softserve Lead Organiser @ GDG Dnipro Coordinator @ WTM Ukraine
  2. #dfua IoC Principle • High level modules should not depend

    on low level modules. Both level modules should depend only on abstractions. • Abstractions should not depend on details. Details should depend on abstractions.
  3. #dfua Inversion of Control (IoC) Pattern benefits Inversion of Control

    will help you to avoid: • Strong coupling. When changes in one module affect other module. • Weakness. Changes in one part lead to unexpected errors in other part. • Inflexibility. Module is hard to separate from the application for reusing.
  4. #dfua Why Dependency Injection? • Dependencies are configured and injected

    externally, that leads that components can be reused. • We are working with abstractions (interfaces), so any implementation can be easily changed with new one, without pain and minimal changes in codebase. Objects insertion are isolated and decoupled. • Dependencies can be injected into components. We even can inject mock implementation of these dependencies . This makes testing much easier.
  5. #dfua JSR-330 (javax.inject) JSR-330 standard defines DI usage and implementation

    for Java and provides: • Set of annotations (and one interface) for injectable classes; • Standardised Dependency Injection API; • Consistency between DI instruments.
  6. #dfua What is Dagger? • Dagger 1 - originally created

    by Square; • Dagger 2 - re-created by Google, built on top of Dagger 1; • Pure Java library; • Alternative way for instantiate and manage your dependencies.
  7. #dfua Dagger 2 vs Dagger 1 • Injection problems are

    solved using code generation; • No reflection: using dependencies graph, configured at compile-time; • Fully traceable → easy debugging (concrete and clear call stack); • Performance: according to Google more that 15% increase; • Code obfuscation: method dispatch like ‘hand written’ code
  8. #dfua Other DI instruments • Spring (xml, start-time) • Guice

    (JSR-330, Runtime) • Dagger 1 (JSR-330, Runtime) • Dagger 2 (JSR-330, Compile-time) • Tiger (JSR-330, Compile-time)
  9. #dfua @Module @Module
 public class LocationModule {
 
 @Provides
 @Singleton


    LocationManager provideLocationManager() {
 GPSLocationManager manager = new GPSLocationManager();
 return manager;
 }
 }
  10. #dfua @Component @Component(modules = {AppModule.class, LocationModule.class})
 @Singleton
 public interface AppComponent

    {
 void inject(AppSplashActivity activity); void inject(AppLoginActivity activity); void inject(LocationActivity activity);
 }
  11. #dfua @Inject with constructor public class GPSLocationManager implements LocationManager {


    private LocationStore store;
 
 @Inject
 public GPSLocationManager(LocationStore store) {
 this.store = store;
 }
 }
  12. #dfua @Inject with fields public class LocationActivity extends BaseActivity {


    @Inject LocationManager locationManager;
 @Override
 public void onCreate() {
 App.getAppComponent.inject(this);
 }
 }
  13. #dfua public class AppLoginActivity extends BaseActivity {
 
 @Inject
 Lazy<AuthService>

    lazyAuthService;
 @Override
 public void onCreate() {
 App.getAppComponent.inject(this);
 }
 } Lazy @Inject
  14. #dfua public class AppLoginActivity extends BaseActivity {
 
 @Inject Provider<AuthService>

    authServiceProvider; @Override
 protected void onClick() {
 AuthService userAuth = authServiceProvider.get(); AuthService adminAuth = authServiceProvider.get();
 } } Provider @Inject - Factory
  15. #dfua @Module
 public class NetworkModule {
 @Provides @Named("cached")
 @Singleton
 OkHttpClient

    provideOkHttpClient(Cache cache) {
 OkHttpClient client = new OkHttpClient();
 client.setCache(cache);
 return client;
 }
 
 @Provides @Named("non_cached")
 @Singleton
 OkHttpClient provideOkHttpClient() {
 return new OkHttpClient();
 }
 }
 Qualified types
  16. #dfua public class AppLoginActivity extends BaseActivity {
 
 @Inject
 @Named("cached")


    OkHttpClient cachedClient; 
 @Inject
 @Named("non_cached")
 OkHttpClient client;
 } Qualified types with @inject
  17. #dfua Graph generation public class App extends Application {
 


    private static AppComponent appComponent;
 
 @Override
 public void onCreate() {
 super.onCreate();
 appComponent = ComponentInitializer.init();
 }
 
 public final static class ComponentInitializer {
 public static AppComponent init() {
 return DaggerAppComponent.create();
 }
 }
 }
  18. #dfua public final static class ComponentInitializer {
 public static AppComponent

    init() {
 return DaggerAppComponent. builder(). appModule(new AppModule(this)). build();
 }
 } Graph generation
  19. #dfua Activity/Service/etc. Application App Module Network Module Utils Module Context

    Asset Utils Network channel Network Utils Builds Provide 
 Context Provide 
 Network Injects (Fields, Constructors) Provide 
 Assets Provide 
 Net utils Component
  20. #dfua Modules suggestions • Context • System services (e.g. LocationManager)

    • REST service (e.g. Retrofit) • Database manager (e.g. Realm) • Message passing (e.g. EventBus) • Analytics tracker (e.g. Google Analytics)
  21. #dfua Model-View-Presenter DataManager - model layer, holds a reference to

    Retrofit, Database, etc. Presenter Layer - in the “middle” between View layer and Model Layer, doesn’t know anything about Activity/Fragment/View View Layer - combination of Activity/Fragment with implementation of the View interface and XML layout. Holds soft reference to Presenter.
  22. #dfua public class CreateUserContract {
 
 interface Actions {
 void

    registerUser(String email);
 } 
 
 interface View {
 void onUserRegistered(User user);
 void onErrorRegisteringUser(String error);
 }
 } View-Presenter contract
  23. #dfua public class CreateUserPresenter implements CreateUserContract.Actions {
 private final CreateUserContract.View

    view;
 
 @Inject
 public CreateUserPresenter(CreateUserContract.View view) {
 this.view = view;
 }
 
 @Override
 public void registerUser(String email) {
 }
 } Presenter implementation
  24. #dfua public class CreateUserActivity extends BaseActivity implements CreateUserContract.View {
 


    @Inject CreateUserPresenter presenter;
 
 private void onClick(View v) {
 presenter.registerUser("[email protected]");
 }
 
 @Override
 public void onUserRegistered(User user) {
 }
 
 @Override
 public void onErrorRegisteringUser() {
 }
 } View implementation
  25. #dfua @Module
 public class CreateUserModule {
 
 private final CreateUserContract.View

    view;
 
 public CreateUserModule(CreateUserContract.View view) {
 this.view = view;
 }
 
 @Provides
 public CreateUserContract.View provideView() {
 return view;
 }
 } Module
  26. #dfua @Singleton
 @Component(modules = {AppModule.class,NetworkModule.class})
 public interface AppComponent {
 


    CreateUserComponent plus(CreateUserModule module);
 
 void inject(AppLoginActivity activity);
 } AppComponent
  27. #dfua public class CreateUserActivity extends BaseActivity implements CreateUserContract.View {
 


    @Inject
 CreateUserPresenter presenter;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 buildAndInjectComponent();
 }
 
 private void buildAndInjectComponent() {
 App.getAppComponent().plus(new CreateUserModule(this)).inject(this);
 }
 } Injection
  28. #dfua Dagger pros • Performance - unlike other reflection-based frameworks

    it uses annotation processors, fast and flexible • Single module configuration - localised in a single point in our app, and we have full control over it • Separated and Isolated application logic • Portability - this makes your code used again and again
  29. #dfua • Unit test - inject one object instead of

    another; • Integration tests - easily mock any part of application; • Scopes - injection can be related to specific part of application; • Object decoupling - less connection between objects, code changes and refactoring is easier. Dagger pros
  30. #dfua Dagger cons • Strong types validation (e.g no injection

    from the base classes). • Component implementation (e.g DaggerAppComponent requires rebuilding the project to appear). • In case of any injection-related compile errors previously generated classes will disappear.
  31. #dfua AppLoginActivity.Java public class AppLoginActivity extends AppCompatActivity {
 
 @Inject


    AuthService auth;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 App.getAppComponent().inject(this);
 }
 } Workaround for strong types validation
  32. #dfua BaseActivity.Java public abstract class BaseActivity extends AppCompatActivity {
 


    @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 inject(App.getAppComponent());
 }
 
 protected abstract void inject(AppComponent component);
 } Moving injection to the super type
  33. #dfua AppLoginActivity.Java public class AppLoginActivity extends BaseActivity {
 
 @Inject


    AuthService auth;
 
 @Override
 protected void inject(AppComponent component) {
 component.inject(this);
 } } Workaround for strong types validation