My way to clean android V2

41
My way to clean Android v2 Christian Panadero http://panavtec.me @PaNaVTEC Github - PaNaVTEC My Way to clean Android V2

Transcript of My way to clean android V2

Page 1: My way to clean android V2

My way to clean Android v2

Christian Panadero

http://panavtec.me @PaNaVTEC

Github - PaNaVTEC

My Way to clean Android V2

Page 2: 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

Page 3: My way to clean android V2

My way to clean Android v2

“My way to clean Android”

Page 4: My way to clean android V2

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?

Page 5: My way to clean android V2

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

Page 6: My way to clean android V2

My way to clean Android v2

Niveles de abstracción

Presenters

Interactors

Entidades

Repository

Data sources

UI

Abstractions

Page 7: My way to clean android V2

My way to clean Android v2

Regla de dependencias

Presenters

Interactors

Entidades

Repository

Data sources

UI

Abstractions

Page 8: My way to clean android V2

My way to clean Android v2

• App (UI, DI y detalles de implementación)

• Presentation

• Domain y Entities

• Repository

• Data Sources

Modelando el proyecto

Page 9: My way to clean android V2

My way to clean Android v2

Dependencias del proyecto

App

Presenters Domain Data

Entities

Repository

Page 10: My way to clean android V2

My way to clean Android v2

Flow

View

Presenter

Presenter

Interactor

Interactor

Interactor

Interactor

Repository

Repository

DataSource

DataSource

DataSource

Page 11: My way to clean android V2

My way to clean Android v2

UI: MVPViewPresenter(s)

Model

Eventos

Rellena la vista

Acciones Resultados de esas acciones

Page 12: My way to clean android V2

My way to clean Android v2

UI: MVP - Viewpublic 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(); } }

Page 13: My way to clean android V2

My way to clean Android v2

UI: MVP - Presenterpublic class MainPresenter extends Presenter<MainView> {

public void onResume() { refreshContactList(); } public void onRefresh() { getView().refreshUi(); refreshContactList(); }

}

Page 14: My way to clean android V2

My way to clean Android v2

UI: MVP - Presenter

@ThreadDecoratedViewpublic interface MainView extends PresenterView { void showGetContactsError(); void refreshContactsList(List<PresentationContact> contacts); void refreshUi(); }

public interface PresenterView { void initUi(); }

prevents spoiler :D

Page 15: My way to clean android V2

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

Page 16: My way to clean android V2

My way to clean Android v2

onConfigurationChange Hellpublic 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(); }

Page 17: My way to clean android V2

My way to clean Android v2

Presentation - Domain (ASYNC)

Presenter Invoker

InteractorOutput

Invoker IMP

Interactor

Page 18: My way to clean android V2

My way to clean Android v2

Presentation - Domain (SYNC)

Presenter Invoker

Future

Invoker IMP

Interactor

.get();.cancel();

Page 19: My way to clean android V2

My way to clean Android v2

Presentation - Domainpublic 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); }

}

Page 20: My way to clean android V2

My way to clean Android v2

Domain - Interactorpublic 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); } }

Page 21: My way to clean android V2

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(); } }); }

}

Page 22: My way to clean android V2

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; } }

Page 23: My way to clean android V2

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); }

}

@ThreadDecoratedViewpublic interface MainView extends PresenterView { … }

Page 24: My way to clean android V2

My way to clean Android v2

Repository

NetworkData Source

BDDData Source

RepositoryModel

Data

Page 25: My way to clean android V2

My way to clean Android v2

Repository Interface

public interface ContactsRepository { List<Contact> obtainContacts() throws RetrieveContactsException; Contact obtain(String md5) throws ObtainContactException; }

Page 26: My way to clean android V2

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; }

Page 27: My way to clean android V2

My way to clean Android v2

Data source

Model

Data source Imp

Data source

Mapper

Page 28: My way to clean android V2

My way to clean Android v2

Data source Interface

public interface ContactsNetworkDataSource { public List<Contact> obtainContacts() throws ContactsNetworkException …; }

Page 29: My way to clean android V2

My way to clean Android v2

Data source impprivate 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(); } }

Page 30: My way to clean android V2

My way to clean Android v2

Caching Strategypublic 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(); } }

Page 31: My way to clean android V2

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(); } }

Page 32: My way to clean android V2

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

Page 33: My way to clean android V2

My way to clean Android v2

– Uncle Bob

“Make implementation details swappable”

Page 34: My way to clean android V2

My way to clean Android v2

Picassopublic 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); } }

Page 35: My way to clean android V2

My way to clean Android v2

ErrorManagerpublic 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(); } }

Page 36: My way to clean android V2

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

Page 37: My way to clean android V2

My way to clean Android v2

– Uncle Bob

“Clean code. The last programming language”

Page 38: My way to clean android V2

My way to clean Android v2

In Uncle Bob we trust

Page 39: My way to clean android V2

My way to clean Android v2

https://github.com/PaNaVTEC/Clean-Contacts

Show me the code!

Page 40: My way to clean android V2

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

Page 41: My way to clean android V2

My way to clean Android v2

¿Preguntas?

Christian Panadero

http://panavtec.me @PaNaVTEC

Github - PaNaVTEC