SlideShare a Scribd company logo
Building maintainable
app with MVP and
Dagger2
KRISTIJAN JURKOVIĆ
ANDROID TEAM LEAD @ INFINUM
We're hiring.
HTTPS://INFINUM.CO/CAREERS
We're an independent
design & development
agency.
Building maintainable app #droidconzg
INFINUM
• 90+ people in 3 offices
• 15 android developers
• hundreds of projects
OUR BIGGEST ISSUES?
“Sometimes when you fill a vacuum, it still
sucks.”
― Dennis Ritchie
MVP TO THE RESCUE?
PROGRAM TO INTERFACES
NOT IMPLEMENTATIONS
ModelPresenterView
LoginActivity LoginPresenterImpl LoginInteractorImpl
LoginView LoginPresenter LoginInteractor
showLoading()
hideLoading()
setUsernameError()
setPasswordError()
showLoading()
hideLoading()
setUsernameError()
setPasswordError()
login(username, pass)
loginPresenter loginView
loginInteractor
login(username, pass) login(username, pass,
listener)
login(username, pass,
listener)
VIEW PRESENTER MODEL
public interface HomeView {
...
}
public interface HomePresenter {
...
}
public interface CurrencyInteractor {
...
}
VIEW
PRESENTER
MODEL
public interface HomeView {
...
}
VIEW
public class HomeActivity
extends BaseActivity
implements HomeView {
// this is an interface
HomePresenter presenter;
...
}
public interface HomePresenter {
...
}
PRESENTER
public class HomePresenterImpl
implements HomePresenter {
// interface
private HomeView view;
// and another interface
private CurrencyInteractor interactor;
public HomePresenterImpl(
HomeView view, CurrencyInteractor interactor) {
this.view = view;
this.interactor = interactor;
}
...
}
public interface CurrencyInteractor {
...
}
MODEL
public class CurrencyInteractorImpl
implements CurrencyInteractor {
...
}
HOW SHOULD I GET MY
CONTENT?
public interface HomeView {
void showCurrencies(List<Currency> currencies);
}
public interface HomePresenter {
void loadCurrencyList();
}
public interface CurrencyInteractor {
void getCurrencyList(CurrencyListener listener);
}
public class HomeActivity
extends BaseActivity
implements HomeView {
private void init() {
presenter = new HomePresenterImpl(this,
new CurrencyInteractorImpl());
presenter.getCurrencyList();
}
@Override
public void showCurrencies(List<Currency> currencies) {
// display data 

}
}
public class HomePresenterImpl
implements HomePresenter {
...
@Override
public void loadCurrencyList() {
interactor.getCurrencyList(...);
}
}
public class CurrencyInteractorImpl
implements CurrencyInteractor {
...
@Override
public void getCurrencyList(
CurrencyListener listener) {
// do API/DB call
// return result with listener
}
}
VIEW SHOULDN’T CREATE ITS
DEPENDENCIES
DEPENDENCY INJECTION
JSR 330
• 5 annotations - @Named, @Inject, @Qualifier, @Scope,
@Singleton
• 1 interface - Provider<T>
DAGGER2 TO THE RESCUE
DAGGER 2
• @Module, @Provides, @Component, @Subcomponent,
ScopedProvider
• Injection into Fields, Constructors, Methods
• Each @Inject has to have its @Provides
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
@Module
public class ApiModule {
@Provides
@Singleton
public ApiService provideApiService(
OkHttpClient client, BaseUrl endpoint,
Converter.Factory converter) {
return RestUtils.createApiService(
client, endpoint, converter,
ApiService.class);
}
}
@Module
public class ApiModule {
@Provides
@Singleton
public ApiService provideApiService(
OkHttpClient client, BaseUrl endpoint,
Converter.Factory converter) {
return RestUtils.createApiService(
client, endpoint, converter,
ApiService.class);
}
}
@Module
public class ApiModule {
@Provides
@Singleton
public ApiService provideApiService(
OkHttpClient client, BaseUrl endpoint,
Converter.Factory converter) {
return RestUtils.createApiService(
client, endpoint, converter,
ApiService.class);
}
}
@Module
public class GsonConverterModule {
@Provides
@Singleton
public Converter.Factory
provideConverter(Gson gson) {
return GsonConverterFactory.create(gson);
}
}
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
EXECUTORS
MODULE
@Component(modules = {
HostModule.class,
GsonConverterModule.class,
ClientModule.class,
LoggerModule.class,
ExecutorsModule.class,
ApiModule.class,
GsonModule.class
})
@Singleton
public interface AppComponent {
}
public class MyApplication extends Application {
protected AppComponent appComponent;
protected void init() {
appComponent = DaggerAppComponent.create();
}
}
HOW CAN WE REUSE THAT
IN OUR ACTIVITIES?
public class HomeActivity
extends BaseActivity
implements HomeView {
private void init() {
presenter = new HomePresenterImpl(this,
new CurrencyInteractorImpl());
presenter.getCurrencyList();
}
@Override
public void showCurrencies(List<Currency> currencies) {
// display data 

}
}
• Inject presenter into view
• Inject view and interactor into presenter
@Module
public class HomeModule {
private HomeView view;
public HomeModule(HomeView view) {
this.view = view;
}
@Provides
public HomeView provideView() {
return view;
}
@Provides
public HomePresenter providePresenter(HomePresenterImpl presenter) {
return presenter;
}
@Provides
public CurrencyInteractor provideInteractor(
CurrencyInteractorImpl interactor) {
return interactor;
}
}
@Module
public class HomeModule {
private HomeView view;
public HomeModule(HomeView view) {
this.view = view;
}
@Provides
public HomeView provideView() {
return view;
}
@Provides
public HomePresenter providePresenter(HomePresenterImpl presenter) {
return presenter;
}
@Provides
public CurrencyInteractor provideInteractor(
CurrencyInteractorImpl interactor) {
return interactor;
}
}
@Module
public class HomeModule {
private HomeView view;
public HomeModule(HomeView view) {
this.view = view;
}
@Provides
public HomeView provideView() {
return view;
}
@Provides
public HomePresenter providePresenter(HomePresenterImpl presenter) {
return presenter;
}
@Provides
public CurrencyInteractor provideInteractor(
CurrencyInteractorImpl interactor) {
return interactor;
}
}
public class CurrencyInteractorImpl
implements CurrencyInteractor {
@Inject
public CurrencyInteractorImpl(ApiService service) {
}
}
public class CurrencyInteractorImpl
implements CurrencyInteractor {
@Inject
public CurrencyInteractorImpl(ApiService service) {
}
}
@Module
public class HomeModule {
private HomeView view;
public HomeModule(HomeView view) {
this.view = view;
}
@Provides
public HomeView provideView() {
return view;
}
@Provides
public HomePresenter providePresenter(HomePresenterImpl presenter) {
return presenter;
}
@Provides
public CurrencyInteractor provideInteractor(
CurrencyInteractorImpl interactor) {
return interactor;
}
}
public class HomePresenterImpl
implements HomePresenter {
@Inject
public HomePresenterImpl(HomeView view,
CurrencyInteractor interactor) {
this.view = view;
this.interactor = interactor;
}
}
public class HomeActivity
extends BaseActivity
implements HomeView {
@Inject
HomePresenter presenter;
}
@Subcomponent(modules = HomeModule.class)
public interface HomeComponent {
void inject(HomeActivity activity);
}
WHAT’S THAT
“SUBCOMPONENT” THING
YOU MENTIONED?
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
HOME
MODULE
HOMECOMPONENT
EXECUTORS
MODULE
@Component(modules = {
...
})
@Singleton
public interface AppComponent {
HomeComponent plus(HomeModule module);
}
public abstract class BaseActivity
extends AppCompatActivity {
Override
protected void onCreate(Bundle savedInstanceState) {
...
injectDependencies(MyApplication.getAppComponent());
}
protected abstract
void injectDependencies(AppComponent appComponent);
}
public class HomeActivity
extends BaseActivity
implements HomeView {
protected void
injectDependencies(AppComponent appComponent) {
appComponent
.plus(new HomeModule(this))
.inject(this);
}
}
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
HOME
MODULE
HOMECOMPONENT
SESSIONCOMPONENT
SESSION
MODULE
EXECUTORS
MODULE
SATISFACTION LEVEL 9001
“If you don’t like testing your product, most
likely your customers won’t like to test it
either.”
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
EXECUTORS
MODULE
APP COMPONENT
HOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
EXECUTORS
MODULE
APPTESTCOMPONENT
MOCKHOST
MODULE
CONVERTER
MODULE
CLIENT
MODULE
LOGGER
MODULE
API
MODULE
GSON
MODULE
SYNC
EXECUTORS
MODULE
@Component(modules = {
...
MockHostModule.class,
SynchronousExecutorsModule.class,
...
})
@Singleton
public interface AppTestComponent extends AppComponent {
void inject(MyTestApplication app);
}
@Component(modules = {
...
MockHostModule.class,
SynchronousExecutorsModule.class,
...
})
@Singleton
public interface AppTestComponent extends AppComponent {
void inject(MyTestApplication app);
}
@Component(modules = {
...
MockHostModule.class,
SynchronousExecutorsModule.class,
...
})
@Singleton
public interface AppTestComponent extends AppComponent {
void inject(MyTestApplication app);
}
public class MyTestApplication
extends MyApplication
implements TestLifecycleApplication {
@Override
protected void init() {
appComponent = DaggerAppTestComponent.create();
}
}
protected void enqueueResponse(String filename) {
String body = ResourceUtils.readFromFile(filename);
MockResponse mockResponse =
new MockResponse()
.setBody(body)
.setResponseCode(HttpURLConnection.HTTP_OK);
mockWebServer.enqueue(mockResponse);
}
@Override
public void setup() throws Exception {
super.setup();
controller = Robolectric
.buildActivity(MockActivity.class)
.create()
.start()
.resume()
.visible();
fragment = DashboardDrivingModeFragment.newInstance();
controller.get().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment, null)
.commit();
ButterKnife.bind(this, fragment.getView());
}
@Test
public void testEmptyStateNotVisible() {
enqueueResponse(“rest-currency-response.json”);
btnCurrencyList.performClick();
assertThat(emptyView).isNotVisible();
}
THINGS TO REMEMBER
• Orientation change
THINGS TO REMEMBER
• Dagger2 is a powerful tool - make good use of it
• Save yourselves from regression bugs
REFERENCES
• http://antonioleiva.com/mvp-android/
• https://medium.com/@czyrux/presenter-surviving-
orientation-changes-with-
loaders-6da6d86ffbbf#.xou7c71uz
• http://frogermcs.github.io/dependency-injection-with-
dagger-2-custom-scopes/
• https://www.youtube.com/watch?v=oK_XtfXPkqw
We're hiring.
HTTPS://INFINUM.CO/CAREERS
Any questions?
KRISTIJAN.JURKOVIC@INFINUM.CO
@KJURKOVIC
Visit infinum.co or find us on social networks:
infinum.co infinumco infinumco infinum

More Related Content

PDF
Building maintainable app
PDF
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
PDF
ChtiJUG - Introduction à Angular2
PDF
Technozaure - Angular2
PDF
Sharper Better Faster Dagger ‡ - Droidcon SF
PDF
A friend in need - A JS indeed
PDF
Commit University - Exploring Angular 2
PPTX
Angular2 + rxjs
Building maintainable app
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
ChtiJUG - Introduction à Angular2
Technozaure - Angular2
Sharper Better Faster Dagger ‡ - Droidcon SF
A friend in need - A JS indeed
Commit University - Exploring Angular 2
Angular2 + rxjs

What's hot (20)

PDF
Using hilt in a modularized project
PDF
Data Flow Patterns in Angular 2 - Sebastian Müller
PPTX
Angular modules in depth
PPTX
Angular Workshop_Sarajevo2
PDF
Using Dagger in a Clean Architecture project
PDF
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
PDF
Solid angular
PPT
Angular 8
PDF
Dagger 2. Right way to do Dependency Injection
PPTX
Dagger 2. The Right Way to Dependency Injections
PDF
Seven Versions of One Web Application
PDF
The productive developer guide to Angular 2
PDF
An introduction to Angular2
PDF
AngularJS - dependency injection
PDF
Dagger 2 vs koin
PDF
Guice tutorial
PDF
Creating Alloy Widgets
PDF
Angular 2: core concepts
PDF
Advanced Dagger talk from 360andev
PDF
Di code steps
Using hilt in a modularized project
Data Flow Patterns in Angular 2 - Sebastian Müller
Angular modules in depth
Angular Workshop_Sarajevo2
Using Dagger in a Clean Architecture project
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Solid angular
Angular 8
Dagger 2. Right way to do Dependency Injection
Dagger 2. The Right Way to Dependency Injections
Seven Versions of One Web Application
The productive developer guide to Angular 2
An introduction to Angular2
AngularJS - dependency injection
Dagger 2 vs koin
Guice tutorial
Creating Alloy Widgets
Angular 2: core concepts
Advanced Dagger talk from 360andev
Di code steps
Ad

Similar to Building maintainable app #droidconzg (20)

PPTX
Android architecture
PDF
Real World Dependency Injection - oscon13
PDF
Quick Start to iOS Development
PDF
Real World Dependency Injection - IPC11 Spring Edition
PDF
Google GIN
PDF
1/3 : introduction to CDI - Antoine Sabot-Durand
PDF
Devoxx 2012 (v2)
PDF
S313937 cdi dochez
PDF
Workshop 13: AngularJS Parte II
PDF
Introduction to cdi given at java one 2014
PDF
Introduction to CDI
PDF
A tour through Swift attributes
PDF
Angular Dependency Injection
PDF
Real World Dependency Injection - phpday
PPTX
Angular workshop - Full Development Guide
PDF
Proxy Deep Dive JUG Saxony Day 2015-10-02
PDF
What is your money doing?
PDF
Parsley & Flex
PDF
Web automation with #d8rules (European Drupal Days 2015)
Android architecture
Real World Dependency Injection - oscon13
Quick Start to iOS Development
Real World Dependency Injection - IPC11 Spring Edition
Google GIN
1/3 : introduction to CDI - Antoine Sabot-Durand
Devoxx 2012 (v2)
S313937 cdi dochez
Workshop 13: AngularJS Parte II
Introduction to cdi given at java one 2014
Introduction to CDI
A tour through Swift attributes
Angular Dependency Injection
Real World Dependency Injection - phpday
Angular workshop - Full Development Guide
Proxy Deep Dive JUG Saxony Day 2015-10-02
What is your money doing?
Parsley & Flex
Web automation with #d8rules (European Drupal Days 2015)
Ad

Recently uploaded (20)

PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PDF
Encapsulation theory and applications.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
1. Introduction to Computer Programming.pptx
PDF
Empathic Computing: Creating Shared Understanding
PPTX
Spectroscopy.pptx food analysis technology
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Machine learning based COVID-19 study performance prediction
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
Big Data Technologies - Introduction.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
A comparative analysis of optical character recognition models for extracting...
SOPHOS-XG Firewall Administrator PPT.pptx
Encapsulation theory and applications.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Electronic commerce courselecture one. Pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
1. Introduction to Computer Programming.pptx
Empathic Computing: Creating Shared Understanding
Spectroscopy.pptx food analysis technology
Network Security Unit 5.pdf for BCA BBA.
Machine learning based COVID-19 study performance prediction
Advanced methodologies resolving dimensionality complications for autism neur...
Assigned Numbers - 2025 - Bluetooth® Document
Dropbox Q2 2025 Financial Results & Investor Presentation
Big Data Technologies - Introduction.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
Diabetes mellitus diagnosis method based random forest with bat algorithm
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
A comparative analysis of optical character recognition models for extracting...

Building maintainable app #droidconzg