SlideShare una empresa de Scribd logo
1 de 41
Descargar para leer sin conexión
My way to clean Android v2
Christian Panadero
http://panavtec.me
@PaNaVTEC
Github - PaNaVTEC
My Way to clean Android
V2
My way to clean Android v2
Agradecimientos
Fernando Cejas
Jorge Barroso
Pedro Gomez
Sergio Rodrigo
@fernando_cejas
@flipper83
@pedro_g_s
@srodrigoDev
Android developer en Sound CloudAndroid developer en Karumi
Cofounder & Android expert en Karumi
Android developer en Develapps
Alberto Moraga
Carlos Morera
@albertomoraga
@CarlosMChica
iOS Developer en Selltag
Android Developer en Viagogo
My way to clean Android v2
“My way to clean Android”
My way to clean Android v2
• Desacoplado de los frameworks
• Testable
• Desacoplado de la UI
• Desacoplado de BDD
• Desacoplado de cualquier detalle de
implementación
¿Por qué Clean?
My way to clean Android v2
• Patrón command (Invoker, command, receiver)
• Patrón decorator
• Interactors / Casos de uso
• Abstracciones
• Data Source
• Repository
• Procesador de Anotaciones
Conceptos
My way to clean Android v2
Niveles de abstracción
Presenters
Interactors
Entidades
Repository
Data sources
UI
Abstractions
My way to clean Android v2
Regla de dependencias
Presenters
Interactors
Entidades
Repository
Data sources
UI
Abstractions
My way to clean Android v2
• App (UI, DI y detalles de implementación)
• Presentation
• Domain y Entities
• Repository
• Data Sources
Modelando el proyecto
My way to clean Android v2
Dependencias del proyecto
App
Presenters Domain Data
Entities
Repository
My way to clean Android v2
Flow
View
Presenter
Presenter
Interactor
Interactor
Interactor
Interactor
Repository
Repository
DataSource
DataSource
DataSource
My way to clean Android v2
UI: MVP
ViewPresenter(s)
Model
Eventos
Rellena la vista
Acciones Resultados de
esas acciones
My way to clean Android v2
UI: MVP - View
public class MainActivity extends BaseActivity implements MainView {


@Inject MainPresenter presenter;

@Override protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

presenter.attachView(this);

}


@Override protected void onResume() {

super.onResume();

presenter.onResume();

}



@Override public void onRefresh() {

presenter.onRefresh();

}



}
My way to clean Android v2
UI: MVP - Presenter
public class MainPresenter extends Presenter<MainView> {
public void onResume() {

refreshContactList();

}



public void onRefresh() {

getView().refreshUi();

refreshContactList();

}
}
My way to clean Android v2
UI: MVP - Presenter
@ThreadDecoratedView

public interface MainView extends PresenterView {

void showGetContactsError();



void refreshContactsList(List<PresentationContact> contacts);



void refreshUi();

}
public interface PresenterView {

void initUi();

}
prevents spoiler :D
My way to clean Android v2
• El problema de las rotaciones está en la capa de UI
• configurationChange recrea toda la Activity
• onRetainCustomNonConfigurationInstance al rescate!
• Retener el grafo de dagger
onConfigurationChange Hell
My way to clean Android v2
onConfigurationChange Hell
public abstract class BaseActivity extends ActionBarActivity {

@Override protected void onCreate(Bundle savedInstanceState) {

createActivityModule();

}


private void createActivityModule() {

activityInjector = (ActivityInjector)
getLastCustomNonConfigurationInstance();

if (activityInjector == null) {

activityInjector = new ActivityInjector();

activityInjector.createGraph(this, newDiModule());

}

activityInjector.inject(this);

}



@Override public Object onRetainCustomNonConfigurationInstance() {

return activityInjector;

}



protected abstract Object newDiModule();

}
My way to clean Android v2
Presentation - Domain
(ASYNC)
Presenter Invoker
Interactor
Output
Invoker IMP
Interactor
My way to clean Android v2
Presentation - Domain
(SYNC)
Presenter Invoker
Future
Invoker IMP
Interactor
.get();.cancel();
My way to clean Android v2
Presentation - Domain
public class MainPresenter extends Presenter<MainView> {
@Output InteractorOutput<List<Contact>, RetrieveContactsException> output;

public MainPresenter(…) {

InteractorOutputInjector.inject(this);

}
public void onResume() {

interactorInvoker.execute(getContactsInteractor, output);

}
@OnError void onContactsInteractorError(RetrieveContactsException data) {

getView().showGetContactsError();

}
@OnResult void onContactsInteractor(List<Contact> result) {

List<PresentationContact> presentationContacts =
listMapper.modelToData(result);

getView().refreshContactsList(presentationContacts);

}
}
My way to clean Android v2
Domain - Interactor
public class GetContactInteractor implements Interactor<Contact,
ObtainContactException> {



private ContactsRepository repository;

private String contactMd5;



public GetContactInteractor(ContactsRepository repository) {

this.repository = repository;

}



public void setData(String contactMd5) {

this.contactMd5 = contactMd5;

}



@Override public Contact call() throws ObtainContactException {

return repository.obtain(contactMd5);

}

}
My way to clean Android v2
Bye bye thread Hell!
public class DecoratedMainView implements MainView {
@Override public void showGetContactsError() {

this.threadSpec.execute(new Runnable() {

@Override public void run() {

undecoratedView.showGetContactsError();

}

});

}
}
My way to clean Android v2
Bye bye thread Hell!
public abstract class Presenter<V extends PresenterView> {

private V view;

private ThreadSpec mainThreadSpec;



public Presenter(ThreadSpec mainThreadSpec) {

this.mainThreadSpec = mainThreadSpec;

}



public void attachView(V view) {

this.view = ViewInjector.inject(view, mainThreadSpec);

}



public void detachView() {

view = null;

}



public V getView() {

return view;

}

}
My way to clean Android v2
Bye bye thread Hell!
public class MainThreadSpec implements ThreadSpec {



Handler handler = new Handler();



@Override public void execute(Runnable action) {

handler.post(action);

}

}
public abstract class Presenter<V extends PresenterView> {
public void attachView(V view) {

this.view = ViewInjector.inject(view, mainThreadSpec);

}
}
@ThreadDecoratedView

public interface MainView extends PresenterView { … }
My way to clean Android v2
Repository
Network
Data Source
BDD
Data Source
Repository
Model
Data
My way to clean Android v2
Repository Interface
public interface ContactsRepository {


List<Contact> obtainContacts() throws RetrieveContactsException;



Contact obtain(String md5) throws ObtainContactException;


}
My way to clean Android v2
Repository imp
@Override public List<Contact> obtainContacts() throws
RetrieveContactsException {

List<Contact> contacts = null;

try {

contacts = bddDataSource.obtainContacts();

} catch (ObtainContactsBddException … ce) {

try {

contacts = networkDataSource.obtainContacts();

bddDataSource.persist(contacts);

} catch (UnknownObtainContactsException … ue) {

throw new RetrieveContactsException();

} catch (PersistContactsBddException … pe) {

pe.printStackTrace();

}

}

return contacts;

}
My way to clean Android v2
Data source
Model
Data source Imp
Data source
Mapper
My way to clean Android v2
Data source Interface
public interface ContactsNetworkDataSource {



public List<Contact> obtainContacts() throws ContactsNetworkException …;


}
My way to clean Android v2
Data source imp
private ContactsApiService apiService;

private static final Transformer transformer = new
Transformer.Builder().build(ApiContact.class);
@Override public List<Contact> obtainContacts() throws
ContactsNetworkException {

try {

ApiContactsResponse response = apiService.obtainUsers(100);

List<ApiContactResult> results = response.getResults();

List<Contact> contacts = new ArrayList<>();



for (ApiContactResult apiContact : results) {

contacts.add(transform(apiContact.getUser(), Contact.class));

}



return contacts;

} catch (Throwable e) {

throw new ContactsNetworkException();

}

}
My way to clean Android v2
Caching Strategy
public interface CachingStrategy<T> {

boolean isValid(T data);

}
public class TtlCachingStrategy<T extends TtlCachingObject> implements
CachingStrategy<T> {



private final long ttlMillis;



@Override public boolean isValid(T data) {

return (data.getPersistedTime() + ttlMillis) > System.currentTimeMillis();

}



}
My way to clean Android v2
Caching Strategy
@Override public List<Contact> obtainContacts()

throws ObtainContactsBddException … {

try {

List<BddContact> bddContacts = daoContacts.queryForAll();

if (!cachingStrategy.isValid(bddContacts)) {

deleteBddContacts(bddContacts);

throw new InvalidCacheException();

}

ArrayList<Contact> contacts = new ArrayList<>();

for (BddContact bddContact : bddContacts) {

contacts.add(transform(bddContact, Contact.class));

}

return contacts;

} catch (java.sql.SQLException e) {

throw new ObtainContactsBddException();

} catch (Throwable e) {

throw new UnknownObtainContactsException();

}

}
My way to clean Android v2
• La lógica de negocio no sabe de donde
vienen los datos.
• Fácil de cambiar la implementación de
los orígenes de datos.
• En caso de cambio de orígenes de datos
la lógica de negocio no se ve alterada.
Ventajas de Repository
My way to clean Android v2
– Uncle Bob
“Make implementation details
swappable”
My way to clean Android v2
Picasso
public interface ImageLoader {

public void load(String url, ImageView imageView);

public void loadCircular(String url, ImageView imageView);

}
public class PicassoImageLoader implements ImageLoader {

private Picasso picasso;



@Override public void load(String url, ImageView imageView) {

picasso.load(url).into(imageView);

}



@Override public void loadCircular(String url, ImageView imageView) {

picasso.load(url).transform(new CircleTransform()).into(imageView);

}

}
My way to clean Android v2
ErrorManager
public interface ErrorManager {

public void showError(String error);

}
public class SnackbarErrorManagerImp implements ErrorManager {
@Override public void showError(String error) {

SnackbarManager.show(Snackbar.with(activity).text(error));

}
}
public class ToastErrorManagerImp implements ErrorManager {

@Override public void showError(String error) {

Toast.makeText(activity, error, Toast.LENGTH_LONG).show();

}

}
My way to clean Android v2
• Trabaja siempre con abstracciones nunca con
concreciones.
• Usa un buen naming, si ves que hay alguna
figura que has creado que no sabes que nombre
poner, seguramente esté mal modelada.
• Si creas nuevas figuras usa la diana inicial para
asegurarte que las creas en la capa
correspondiente
Consejos
My way to clean Android v2
– Uncle Bob
“Clean code. The last programming
language”
My way to clean Android v2
In Uncle Bob we trust
My way to clean Android v2
https://github.com/PaNaVTEC/Clean-Contacts
Show me the
code!
My way to clean Android v2
• Fernando Cejas - Clean way
• Jorge Barroso - Arquitectura Tuenti
• Pedro Gomez - Dependency Injection
• Pedro Gomez - Desing patterns
• Uncle Bob - The clean architecture
• PaNaVTEC - Clean without bus
Referencias
My way to clean Android v2
¿Preguntas?
Christian Panadero
http://panavtec.me
@PaNaVTEC
Github - PaNaVTEC

Más contenido relacionado

La actualidad más candente

Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-final
Droidcon Berlin
 
PROMAND 2014 project structure
PROMAND 2014 project structurePROMAND 2014 project structure
PROMAND 2014 project structure
Alexey Buzdin
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
Droidcon Berlin
 

La actualidad más candente (20)

Dagger 2 - Injeção de Dependência
Dagger 2 - Injeção de DependênciaDagger 2 - Injeção de Dependência
Dagger 2 - Injeção de Dependência
 
JS and patterns
JS and patternsJS and patterns
JS and patterns
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
 
Android Unit Testing With Robolectric
Android Unit Testing With RobolectricAndroid Unit Testing With Robolectric
Android Unit Testing With Robolectric
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-final
 
Sharper Better Faster Dagger ‡ - Droidcon SF
Sharper Better Faster Dagger ‡ - Droidcon SFSharper Better Faster Dagger ‡ - Droidcon SF
Sharper Better Faster Dagger ‡ - Droidcon SF
 
A friend in need - A JS indeed
A friend in need - A JS indeedA friend in need - A JS indeed
A friend in need - A JS indeed
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
 
PROMAND 2014 project structure
PROMAND 2014 project structurePROMAND 2014 project structure
PROMAND 2014 project structure
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
 
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, howTomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
 
Dependency Injection for Android
Dependency Injection for AndroidDependency Injection for Android
Dependency Injection for Android
 
Dependency Injection for Android @ Ciklum speakers corner Kiev 29. May 2014
Dependency Injection for Android @ Ciklum speakers corner Kiev 29. May 2014Dependency Injection for Android @ Ciklum speakers corner Kiev 29. May 2014
Dependency Injection for Android @ Ciklum speakers corner Kiev 29. May 2014
 
Quickly Testing Qt Desktop Applications
Quickly Testing Qt Desktop ApplicationsQuickly Testing Qt Desktop Applications
Quickly Testing Qt Desktop Applications
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
 

Similar a My way to clean android V2

Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
Alexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
C.T.Co
 

Similar a My way to clean android V2 (20)

Devoxx 2012 (v2)
Devoxx 2012 (v2)Devoxx 2012 (v2)
Devoxx 2012 (v2)
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code less
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.
 
Net conf BG xamarin lecture
Net conf BG xamarin lectureNet conf BG xamarin lecture
Net conf BG xamarin lecture
 
Service Oriented Architecture in Magento 2
Service Oriented Architecture in Magento 2Service Oriented Architecture in Magento 2
Service Oriented Architecture in Magento 2
 
Cleaning your architecture with android architecture components
Cleaning your architecture with android architecture componentsCleaning your architecture with android architecture components
Cleaning your architecture with android architecture components
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
From framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytvFrom framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytv
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Binding business data to vaadin components
Binding business data to vaadin componentsBinding business data to vaadin components
Binding business data to vaadin components
 
Appcelerator droidcon15 TLV
Appcelerator droidcon15 TLVAppcelerator droidcon15 TLV
Appcelerator droidcon15 TLV
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)
 
Droidcon Berlin Barcamp 2016
Droidcon Berlin Barcamp 2016Droidcon Berlin Barcamp 2016
Droidcon Berlin Barcamp 2016
 
Ruby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCRuby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVC
 
AngularJS in large applications - AE NV
AngularJS in large applications - AE NVAngularJS in large applications - AE NV
AngularJS in large applications - AE NV
 
ASP.NET MVC Internals
ASP.NET MVC InternalsASP.NET MVC Internals
ASP.NET MVC Internals
 
C++ Interface Versioning
C++ Interface VersioningC++ Interface Versioning
C++ Interface Versioning
 

Último

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Último (20)

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 

My way to clean android V2

  • 1. My way to clean Android v2 Christian Panadero http://panavtec.me @PaNaVTEC Github - PaNaVTEC My Way to clean Android V2
  • 2. My way to clean Android v2 Agradecimientos Fernando Cejas Jorge Barroso Pedro Gomez Sergio Rodrigo @fernando_cejas @flipper83 @pedro_g_s @srodrigoDev Android developer en Sound CloudAndroid developer en Karumi Cofounder & Android expert en Karumi Android developer en Develapps Alberto Moraga Carlos Morera @albertomoraga @CarlosMChica iOS Developer en Selltag Android Developer en Viagogo
  • 3. My way to clean Android v2 “My way to clean Android”
  • 4. My way to clean Android v2 • Desacoplado de los frameworks • Testable • Desacoplado de la UI • Desacoplado de BDD • Desacoplado de cualquier detalle de implementación ¿Por qué Clean?
  • 5. My way to clean Android v2 • Patrón command (Invoker, command, receiver) • Patrón decorator • Interactors / Casos de uso • Abstracciones • Data Source • Repository • Procesador de Anotaciones Conceptos
  • 6. My way to clean Android v2 Niveles de abstracción Presenters Interactors Entidades Repository Data sources UI Abstractions
  • 7. My way to clean Android v2 Regla de dependencias Presenters Interactors Entidades Repository Data sources UI Abstractions
  • 8. My way to clean Android v2 • App (UI, DI y detalles de implementación) • Presentation • Domain y Entities • Repository • Data Sources Modelando el proyecto
  • 9. My way to clean Android v2 Dependencias del proyecto App Presenters Domain Data Entities Repository
  • 10. My way to clean Android v2 Flow View Presenter Presenter Interactor Interactor Interactor Interactor Repository Repository DataSource DataSource DataSource
  • 11. My way to clean Android v2 UI: MVP ViewPresenter(s) Model Eventos Rellena la vista Acciones Resultados de esas acciones
  • 12. My way to clean Android v2 UI: MVP - View public class MainActivity extends BaseActivity implements MainView { 
 @Inject MainPresenter presenter;
 @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 presenter.attachView(this);
 } 
 @Override protected void onResume() {
 super.onResume();
 presenter.onResume();
 }
 
 @Override public void onRefresh() {
 presenter.onRefresh();
 }
 
 }
  • 13. My way to clean Android v2 UI: MVP - Presenter public class MainPresenter extends Presenter<MainView> { public void onResume() {
 refreshContactList();
 }
 
 public void onRefresh() {
 getView().refreshUi();
 refreshContactList();
 } }
  • 14. My way to clean Android v2 UI: MVP - Presenter @ThreadDecoratedView
 public interface MainView extends PresenterView {
 void showGetContactsError();
 
 void refreshContactsList(List<PresentationContact> contacts);
 
 void refreshUi();
 } public interface PresenterView {
 void initUi();
 } prevents spoiler :D
  • 15. My way to clean Android v2 • El problema de las rotaciones está en la capa de UI • configurationChange recrea toda la Activity • onRetainCustomNonConfigurationInstance al rescate! • Retener el grafo de dagger onConfigurationChange Hell
  • 16. My way to clean Android v2 onConfigurationChange Hell public abstract class BaseActivity extends ActionBarActivity {
 @Override protected void onCreate(Bundle savedInstanceState) {
 createActivityModule();
 } 
 private void createActivityModule() {
 activityInjector = (ActivityInjector) getLastCustomNonConfigurationInstance();
 if (activityInjector == null) {
 activityInjector = new ActivityInjector();
 activityInjector.createGraph(this, newDiModule());
 }
 activityInjector.inject(this);
 }
 
 @Override public Object onRetainCustomNonConfigurationInstance() {
 return activityInjector;
 }
 
 protected abstract Object newDiModule();
 }
  • 17. My way to clean Android v2 Presentation - Domain (ASYNC) Presenter Invoker Interactor Output Invoker IMP Interactor
  • 18. My way to clean Android v2 Presentation - Domain (SYNC) Presenter Invoker Future Invoker IMP Interactor .get();.cancel();
  • 19. My way to clean Android v2 Presentation - Domain public class MainPresenter extends Presenter<MainView> { @Output InteractorOutput<List<Contact>, RetrieveContactsException> output;
 public MainPresenter(…) {
 InteractorOutputInjector.inject(this);
 } public void onResume() {
 interactorInvoker.execute(getContactsInteractor, output);
 } @OnError void onContactsInteractorError(RetrieveContactsException data) {
 getView().showGetContactsError();
 } @OnResult void onContactsInteractor(List<Contact> result) {
 List<PresentationContact> presentationContacts = listMapper.modelToData(result);
 getView().refreshContactsList(presentationContacts);
 } }
  • 20. My way to clean Android v2 Domain - Interactor public class GetContactInteractor implements Interactor<Contact, ObtainContactException> {
 
 private ContactsRepository repository;
 private String contactMd5;
 
 public GetContactInteractor(ContactsRepository repository) {
 this.repository = repository;
 }
 
 public void setData(String contactMd5) {
 this.contactMd5 = contactMd5;
 }
 
 @Override public Contact call() throws ObtainContactException {
 return repository.obtain(contactMd5);
 }
 }
  • 21. My way to clean Android v2 Bye bye thread Hell! public class DecoratedMainView implements MainView { @Override public void showGetContactsError() {
 this.threadSpec.execute(new Runnable() {
 @Override public void run() {
 undecoratedView.showGetContactsError();
 }
 });
 } }
  • 22. My way to clean Android v2 Bye bye thread Hell! public abstract class Presenter<V extends PresenterView> {
 private V view;
 private ThreadSpec mainThreadSpec;
 
 public Presenter(ThreadSpec mainThreadSpec) {
 this.mainThreadSpec = mainThreadSpec;
 }
 
 public void attachView(V view) {
 this.view = ViewInjector.inject(view, mainThreadSpec);
 }
 
 public void detachView() {
 view = null;
 }
 
 public V getView() {
 return view;
 }
 }
  • 23. My way to clean Android v2 Bye bye thread Hell! public class MainThreadSpec implements ThreadSpec {
 
 Handler handler = new Handler();
 
 @Override public void execute(Runnable action) {
 handler.post(action);
 }
 } public abstract class Presenter<V extends PresenterView> { public void attachView(V view) {
 this.view = ViewInjector.inject(view, mainThreadSpec);
 } } @ThreadDecoratedView
 public interface MainView extends PresenterView { … }
  • 24. My way to clean Android v2 Repository Network Data Source BDD Data Source Repository Model Data
  • 25. My way to clean Android v2 Repository Interface public interface ContactsRepository { 
 List<Contact> obtainContacts() throws RetrieveContactsException;
 
 Contact obtain(String md5) throws ObtainContactException; 
 }
  • 26. My way to clean Android v2 Repository imp @Override public List<Contact> obtainContacts() throws RetrieveContactsException {
 List<Contact> contacts = null;
 try {
 contacts = bddDataSource.obtainContacts();
 } catch (ObtainContactsBddException … ce) {
 try {
 contacts = networkDataSource.obtainContacts();
 bddDataSource.persist(contacts);
 } catch (UnknownObtainContactsException … ue) {
 throw new RetrieveContactsException();
 } catch (PersistContactsBddException … pe) {
 pe.printStackTrace();
 }
 }
 return contacts;
 }
  • 27. My way to clean Android v2 Data source Model Data source Imp Data source Mapper
  • 28. My way to clean Android v2 Data source Interface public interface ContactsNetworkDataSource {
 
 public List<Contact> obtainContacts() throws ContactsNetworkException …; 
 }
  • 29. My way to clean Android v2 Data source imp private ContactsApiService apiService;
 private static final Transformer transformer = new Transformer.Builder().build(ApiContact.class); @Override public List<Contact> obtainContacts() throws ContactsNetworkException {
 try {
 ApiContactsResponse response = apiService.obtainUsers(100);
 List<ApiContactResult> results = response.getResults();
 List<Contact> contacts = new ArrayList<>();
 
 for (ApiContactResult apiContact : results) {
 contacts.add(transform(apiContact.getUser(), Contact.class));
 }
 
 return contacts;
 } catch (Throwable e) {
 throw new ContactsNetworkException();
 }
 }
  • 30. My way to clean Android v2 Caching Strategy public interface CachingStrategy<T> {
 boolean isValid(T data);
 } public class TtlCachingStrategy<T extends TtlCachingObject> implements CachingStrategy<T> {
 
 private final long ttlMillis;
 
 @Override public boolean isValid(T data) {
 return (data.getPersistedTime() + ttlMillis) > System.currentTimeMillis();
 }
 
 }
  • 31. My way to clean Android v2 Caching Strategy @Override public List<Contact> obtainContacts()
 throws ObtainContactsBddException … {
 try {
 List<BddContact> bddContacts = daoContacts.queryForAll();
 if (!cachingStrategy.isValid(bddContacts)) {
 deleteBddContacts(bddContacts);
 throw new InvalidCacheException();
 }
 ArrayList<Contact> contacts = new ArrayList<>();
 for (BddContact bddContact : bddContacts) {
 contacts.add(transform(bddContact, Contact.class));
 }
 return contacts;
 } catch (java.sql.SQLException e) {
 throw new ObtainContactsBddException();
 } catch (Throwable e) {
 throw new UnknownObtainContactsException();
 }
 }
  • 32. My way to clean Android v2 • La lógica de negocio no sabe de donde vienen los datos. • Fácil de cambiar la implementación de los orígenes de datos. • En caso de cambio de orígenes de datos la lógica de negocio no se ve alterada. Ventajas de Repository
  • 33. My way to clean Android v2 – Uncle Bob “Make implementation details swappable”
  • 34. My way to clean Android v2 Picasso public interface ImageLoader {
 public void load(String url, ImageView imageView);
 public void loadCircular(String url, ImageView imageView);
 } public class PicassoImageLoader implements ImageLoader {
 private Picasso picasso;
 
 @Override public void load(String url, ImageView imageView) {
 picasso.load(url).into(imageView);
 }
 
 @Override public void loadCircular(String url, ImageView imageView) {
 picasso.load(url).transform(new CircleTransform()).into(imageView);
 }
 }
  • 35. My way to clean Android v2 ErrorManager public interface ErrorManager {
 public void showError(String error);
 } public class SnackbarErrorManagerImp implements ErrorManager { @Override public void showError(String error) {
 SnackbarManager.show(Snackbar.with(activity).text(error));
 } } public class ToastErrorManagerImp implements ErrorManager {
 @Override public void showError(String error) {
 Toast.makeText(activity, error, Toast.LENGTH_LONG).show();
 }
 }
  • 36. My way to clean Android v2 • Trabaja siempre con abstracciones nunca con concreciones. • Usa un buen naming, si ves que hay alguna figura que has creado que no sabes que nombre poner, seguramente esté mal modelada. • Si creas nuevas figuras usa la diana inicial para asegurarte que las creas en la capa correspondiente Consejos
  • 37. My way to clean Android v2 – Uncle Bob “Clean code. The last programming language”
  • 38. My way to clean Android v2 In Uncle Bob we trust
  • 39. My way to clean Android v2 https://github.com/PaNaVTEC/Clean-Contacts Show me the code!
  • 40. My way to clean Android v2 • Fernando Cejas - Clean way • Jorge Barroso - Arquitectura Tuenti • Pedro Gomez - Dependency Injection • Pedro Gomez - Desing patterns • Uncle Bob - The clean architecture • PaNaVTEC - Clean without bus Referencias
  • 41. My way to clean Android v2 ¿Preguntas? Christian Panadero http://panavtec.me @PaNaVTEC Github - PaNaVTEC