Slide 1

Slide 1 text

Android development like a pro #AndroidDevPro September 29, 2015

Slide 2

Slide 2 text

Israel Camacho September 29, 2015 Android Engineer at Twitter #AndroidDevPro

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Fragment

Slide 5

Slide 5 text

Fragment AsyncTask

Slide 6

Slide 6 text

Fragment AsyncTask Loader

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

What is your goal?

Slide 11

Slide 11 text

Reliable, Scalable and Maintainable

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Deliver

Slide 14

Slide 14 text

Deliver Really

Slide 15

Slide 15 text

Deliver Really Awesome

Slide 16

Slide 16 text

Deliver Really Awesome Features

Slide 17

Slide 17 text

Deliver Really Awesome Features Fast

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Reliable, Scalable and Maintainable

Slide 20

Slide 20 text

Architecture Test

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Fragments

Slide 23

Slide 23 text

Pros Encapsulates full features (multiples views, asynctasks, loaders). Reusable between different Activities.

Slide 24

Slide 24 text

Burrito design pattern

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

It doesn’t help to decouple your business logic!

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

WHY!?

Slide 33

Slide 33 text

WHY!?

Slide 34

Slide 34 text

Alternatives Single activity + navigation manager Many activities with reusable views

Slide 35

Slide 35 text

LaunchActivity NavigationManager Uri: “”

Slide 36

Slide 36 text

LaunchActivity NavigationManager startScreen(Screen1.class) Uri: “”

Slide 37

Slide 37 text

LaunchActivity NavigationManager startScreen(Screen1.class) inflates(Screen1.class) Uri: “screen1”

Slide 38

Slide 38 text

Screen1 URI: screen1 LaunchActivity NavigationManager startScreen(Screen1.class) inflates(Screen1.class) Uri: “screen1”

Slide 39

Slide 39 text

Screen1 URI: screen1 LaunchActivity NavigationManager startScreen(Screen1.class) inflates(Screen1.class) Uri: “screen1” User starts screen 2

Slide 40

Slide 40 text

Screen1 URI: screen1 LaunchActivity NavigationManager inflates(Screen1.class) startScreen(Screen2.class) Uri: “screen1” User starts screen 2

Slide 41

Slide 41 text

Screen1 URI: screen1 LaunchActivity Screen2 URI: screen2 NavigationManager startScreen(Screen2.class) Uri: “screen1/screen2” inflates(Screen2class) User starts screen 2

Slide 42

Slide 42 text

LET ME EXPLAIN YOU ANDROID LIKE A PRO

Slide 43

Slide 43 text

Let’s make an app

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

“Decouple your app from implementation details" - Anonymous

Slide 47

Slide 47 text

public interface ImageLoader { void load(ImageView view, String url); void loadWithTransformation(ImageView view, String url, Transformation transformation); }

Slide 48

Slide 48 text

public class PicassoImageLoader implements ImageLoader { private final Picasso picasso; … @Override public void load(ImageView view, String url) { picasso.load(url).into(view); } @Override public void loadWithTransformation(ImageView view, String url, Transformation transformation) { picasso.load(url).transform(transformation).into(view); } }

Slide 49

Slide 49 text

public class GlideImageLoader implements ImageLoader { private final Glide glide; … @Override public void load(ImageView view, String url) { glide.load(url).into(view); } @Override public void loadWithTransformation(ImageView view, String url, Transformation transformation) { glide.load(url).transform(transformation).into(view); } }

Slide 50

Slide 50 text

Common UI

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

Toolbar DrawerLayout

Slide 53

Slide 53 text

public interface ScreenContainer { /** * The root {@link android.view.ViewGroup} into which the activity should place its contents. */ ViewGroup bind(AppCompatActivity activity); /** * Returns the drawerLayout of this window. * */ DrawerLayout getDrawerLayout(); }

Slide 54

Slide 54 text

public abstract class EffectiveActivity extends AppCompatActivity { private ViewGroup mainFrame; private ScreenContainerImpl screenContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); screenContainer = new ScreenContainerImpl(); mainFrame = screenContainer.bind(this); getLayoutInflater().inflate(getLayout(), mainFrame); ButterKnife.bind(this); } @NonNull abstract int getLayout(); }

Slide 55

Slide 55 text

public abstract class EffectiveActivity extends AppCompatActivity { private ViewGroup mainFrame; private ScreenContainerImpl screenContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); screenContainer = new ScreenContainerImpl(); mainFrame = screenContainer.bind(this); getLayoutInflater().inflate(getLayout(), mainFrame); ButterKnife.bind(this); } @NonNull abstract int getLayout(); }

Slide 56

Slide 56 text

public abstract class EffectiveActivity extends AppCompatActivity { private ViewGroup mainFrame; private ScreenContainerImpl screenContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); screenContainer = new ScreenContainerImpl(); mainFrame = screenContainer.bind(this); getLayoutInflater().inflate(getLayout(), mainFrame); ButterKnife.bind(this); } @NonNull abstract int getLayout(); }

Slide 57

Slide 57 text

public abstract class EffectiveActivity extends AppCompatActivity { private ViewGroup mainFrame; private ScreenContainerImpl screenContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); screenContainer = new ScreenContainerImpl(); mainFrame = screenContainer.bind(this); getLayoutInflater().inflate(getLayout(), mainFrame); ButterKnife.bind(this); } @NonNull abstract int getLayout(); }

Slide 58

Slide 58 text

MVP Clean Architecture

Slide 59

Slide 59 text

View Presenter Model User Interaction

Slide 60

Slide 60 text

View Presenter Model User Interaction notify user event

Slide 61

Slide 61 text

View Presenter Model User Interaction notify user event request data

Slide 62

Slide 62 text

View Presenter Model User Interaction notify user event request data delivers entities

Slide 63

Slide 63 text

View Presenter Model User Interaction notify user event request data delivers entities update UI with entities

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

View

Slide 66

Slide 66 text

public interface TopImagesListView { void setImages(List images); void logout(); }

Slide 67

Slide 67 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpView(); presenter = new TopImagesListPresenterImpl(); presenter.create(); } @Override public void setImages(List images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }

Slide 68

Slide 68 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpView(); presenter = new TopImagesListPresenterImpl(); presenter.create(); } @Override public void setImages(List images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }

Slide 69

Slide 69 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpView(); presenter = new TopImagesListPresenterImpl(); presenter.create(); } @Override public void setImages(List images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }

Slide 70

Slide 70 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpView(); presenter = new TopImagesListPresenterImpl(); presenter.create(); } @Override public void setImages(List images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }

Slide 71

Slide 71 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpView(); presenter = new TopImagesListPresenterImpl(); presenter.create(); } @Override public void setImages(List images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }

Slide 72

Slide 72 text

Presenter

Slide 73

Slide 73 text

public interface TopImagesListPresenter extends Presenter { void create(); void setView(TopImagesListView view); }

Slide 74

Slide 74 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 75

Slide 75 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 76

Slide 76 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 77

Slide 77 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 78

Slide 78 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 79

Slide 79 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 80

Slide 80 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model; private TopImagesListView view; private List viewArticles; … @Override public void create() { if (viewImages == null || viewImages.size() == 0) { viewImages = new ArrayList<>(); model.getMostRtImages(new WeakCallback(view, viewImages)); } else { if (view != null) { view.setImage(articles); } } } … }

Slide 81

Slide 81 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { … private static class WeakCallback extends Callback> { private WeakReference view; private List imagesList; … @Override public void success(Result> result) { if (view.get() != null) { imagesList.addAll(result.data); view.get().setImage(result.data); } } @Override public void failure(TwitterException e) { if (view.get() != null) { view.get().logout(); } } } … }

Slide 82

Slide 82 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { … private static class WeakCallback extends Callback> { private WeakReference view; private List imagesList; … @Override public void success(Result> result) { if (view.get() != null) { imagesList.addAll(result.data); view.get().setImage(result.data); } } @Override public void failure(TwitterException e) { if (view.get() != null) { view.get().logout(); } } } … }

Slide 83

Slide 83 text

public class TopImagesListPresenterImpl implements TopImagesListPresenter { … private static class WeakCallback extends Callback> { private WeakReference view; private List imagesList; … @Override public void success(Result> result) { if (view.get() != null) { imagesList.addAll(result.data); view.get().setImage(result.data); } } @Override public void failure(TwitterException e) { if (view.get() != null) { view.get().logout(); } } } … }

Slide 84

Slide 84 text

Model

Slide 85

Slide 85 text

public interface TopImageListModel { void getMostRtImages(Callback> articles); }

Slide 86

Slide 86 text

public class TopImageListModelImpl implements TopImageListModel { private final CustomApiClient client; ... @Override public void getMostRtImages(final Callback> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 87

Slide 87 text

public class TopImageListModelImpl implements TopImageListModel { private final CustomApiClient client; ... @Override public void getMostRtImages(final Callback> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 88

Slide 88 text

public class TopImageListModelImpl implements TopImageListModel { private final CustomApiClient client; ... @Override public void getMostRtImages(final Callback> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 89

Slide 89 text

public class TopImageListModelImpl implements TopImageListModel { private final CustomApiClient client; ... @Override public void getMostRtImages(final Callback> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 90

Slide 90 text

public class TopImageListModelImpl implements TopImageListModel { private final CustomApiClient client; ... @Override public void getMostRtImages(final Callback> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 91

Slide 91 text

Test

Slide 92

Slide 92 text

View: Test render logic and interaction with presenter, mock Presenter. Presenter: Test that view events invoke the right model method. mock both View and Model. Model: Test the business logic, mock the data source and Presenter.

Slide 93

Slide 93 text

MVP Pros Increases separation of concerns in 3 layers:

Slide 94

Slide 94 text

MVP Pros Increases separation of concerns in 3 layers: Presenter - Handle User events

Slide 95

Slide 95 text

MVP Pros Increases separation of concerns in 3 layers: Passive View - Render logic Presenter - Handle User events

Slide 96

Slide 96 text

MVP Pros Increases separation of concerns in 3 layers: Passive View - Render logic Presenter - Handle User events Model - Business logic

Slide 97

Slide 97 text

MVP Cons

Slide 98

Slide 98 text

MVP Cons BoilerPlate to wire the layers.

Slide 99

Slide 99 text

MVP Cons BoilerPlate to wire the layers. Model can’t be reused since is too tied to the specific use case.

Slide 100

Slide 100 text

MVP Cons BoilerPlate to wire the layers. Model can’t be reused since is too tied to the specific use case. View and Presenter are tied to data objects since they share the same type of object with the Model.

Slide 101

Slide 101 text

Orientation Change

Slide 102

Slide 102 text

PresenterHolder OnDestroy OnCreate Activity save presenter restore presenter onSavedInstanceState remove presenter if Activity is finishing then Running

Slide 103

Slide 103 text

public class EffectiveAndroidApplication extends Application { Map presenterHolder; … public void putPresenter(Class c, Presenter p) { presenterHolder.put(c, p); } public T getPresenter(Class c) { return (T) presenterHolder.get(c); } public void remove(Class c) { presenterMap.remove(c); } }

Slide 104

Slide 104 text

public class PresenterHolder { static volatile PresenterHolder singleton = null; private Map presenterMap; … public void putPresenter(Class c, Presenter p) { singleton.put(c, p); } public T getPresenter(Class c) { return (T) singleton.get(c); } public void remove(Class c) { presenterMap.remove(c); } }

Slide 105

Slide 105 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { … @Override protected void onCreate(Bundle savedInstanceState) { presenter = getPresenterHolder().getPresenter(TopImagesListActivity.class); presenter.create(); } @Override protected void onSaveInstanceState(Bundle bundle) { getPresenterHolder().putPresenter(TopImagesListActivity.class, presenter); } @Override protected void onDestroy() { super.onDestroy(); presenter.setView(null); if (isFinishing()) { getPresenterHolder().remove(TopImagesListActivity.class); } } }

Slide 106

Slide 106 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { … @Override protected void onCreate(Bundle savedInstanceState) { presenter = getPresenterHolder().getPresenter(TopImagesListActivity.class); presenter.create(); } @Override protected void onSaveInstanceState(Bundle bundle) { getPresenterHolder().putPresenter(TopImagesListActivity.class, presenter); } @Override protected void onDestroy() { super.onDestroy(); presenter.setView(null); if (isFinishing()) { getPresenterHolder().remove(TopImagesListActivity.class); } } }

Slide 107

Slide 107 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { … @Override protected void onCreate(Bundle savedInstanceState) { presenter = getPresenterHolder().getPresenter(TopImagesListActivity.class); presenter.create(); } @Override protected void onSaveInstanceState(Bundle bundle) { getPresenterHolder().putPresenter(TopImagesListActivity.class, presenter); } @Override protected void onDestroy() { super.onDestroy(); presenter.setView(null); if (isFinishing()) { getPresenterHolder().remove(TopImagesListActivity.class); } } }

Slide 108

Slide 108 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { … @Override protected void onCreate(Bundle savedInstanceState) { presenter = getPresenterHolder().getPresenter(TopImagesListActivity.class); presenter.create(); } @Override protected void onSaveInstanceState(Bundle bundle) { getPresenterHolder().putPresenter(TopImagesListActivity.class, presenter); } @Override protected void onDestroy() { super.onDestroy(); presenter.setView(null); if (isFinishing()) { getPresenterHolder().remove(TopImagesListActivity.class); } } }

Slide 109

Slide 109 text

public class TopImagesListActivity extends EffectiveActivity implements TopImagesListView { … @Override protected void onCreate(Bundle savedInstanceState) { presenter = getPresenterHolder().getPresenter(TopImagesListActivity.class); presenter.create(); } @Override protected void onSaveInstanceState(Bundle bundle) { getPresenterHolder().putPresenter(TopImagesListActivity.class, presenter); } @Override protected void onDestroy() { super.onDestroy(); presenter.setView(null); if (isFinishing()) { getPresenterHolder().remove(TopImagesListActivity.class); } } }

Slide 110

Slide 110 text

Clean Architecture MVP

Slide 111

Slide 111 text

“The clean architecture” - Uncle Bob

Slide 112

Slide 112 text

View Presenter Repository Presentation Layer Domain Layer Interactor Entity Entity Entity Interactor Interactor Data Layer ViewEntity User Interaction

Slide 113

Slide 113 text

Presentation Layer

Slide 114

Slide 114 text

View Presenter ViewEntity User Interaction

Slide 115

Slide 115 text

Use different entities from the interactor and domain layer.

Slide 116

Slide 116 text

Use different entities from the interactor and domain layer. Decouples from Use case modifications.

Slide 117

Slide 117 text

Use different entities from the interactor and domain layer. Decouples from Use case modifications. Represents data for the presentation layer.

Slide 118

Slide 118 text

Orientation Change

Slide 119

Slide 119 text

ViewEntityHolder OnDestroy OnCreate Activity save ViewEntity restore ViewEntity onSavedInstanceState remove ViewEntity if Activity is finishing then Running

Slide 120

Slide 120 text

Interactors

Slide 121

Slide 121 text

One use case per interactor maximize reusability

Slide 122

Slide 122 text

public interface GetTopArticles { void execute(Callback> articles); }

Slide 123

Slide 123 text

public class GetTopArticlesImpl implements GetTopArticles { private final TweetRepository tweetRepository; … @Override public void execute(final Callback> callback) { tweetRepository.getTimeline(new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 124

Slide 124 text

public class GetTopArticlesImpl implements GetTopArticles { private final TweetRepository tweetRepository; … @Override public void execute(final Callback> callback) { tweetRepository.getTimeline(new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 125

Slide 125 text

public class GetTopArticlesImpl implements GetTopArticles { private final TweetRepository tweetRepository; … @Override public void execute(final Callback> callback) { tweetRepository.getTimeline(new Callback>() { @Override public void success(Result> result) { final List items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }

Slide 126

Slide 126 text

Repository

Slide 127

Slide 127 text

public interface TweetRepository { void getTimeline(final Callback> callback); void getTweet(String tweetId, final Callback callback); }

Slide 128

Slide 128 text

public class TweetRepositoryImpl implements TweetRepository { private final TwitterApiClient client; ... @Override public void getTimeline(final Callback> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, callback); } }

Slide 129

Slide 129 text

public class TweetRepositoryImpl implements TweetRepository { private final TwitterApiClient client; private final TweetCache cache; ... @Override public void getTimeline(final Callback> callback) { if (!cache.isEmpty()) { callback.success(cache.getTimeline()) } else { client.getTimelineService().homeTimeline(200, true, true, true, true,callback); } } }

Slide 130

Slide 130 text

public class TweetRepositoryImpl implements TweetRepository { private final TwitterApiClient client; private final TweetCache cache; private final TweetDB db; ... @Override public void getTimeline(final Callback> callback) { if (!cache.isEmpty()) { callback.success(cache.getTimeline()) } else if (!db.isEmpty()) { callback.success(db.getTimeline()) } else { client.getTimelineService().homeTimeline(200, true, true, true, true,callback); } } }

Slide 131

Slide 131 text

View Presenter Repository Presentation Layer Domain Layer Interactor Entity Entity Entity Interactor Interactor Data Layer ViewEntity User Interaction

Slide 132

Slide 132 text

Clean Architecture Benefits Presentation is decoupled from domain, that allows you to change the presentation pattern at anytime without changing any other layer.

Slide 133

Slide 133 text

Clean Architecture Benefits Domain layer allow new comers to understand use cases of the app. Interactor is just a function that gets an input and returns an output. It doesn’t care about representation or data sources. Domain layer can be a Java module!

Slide 134

Slide 134 text

Clean Architecture Benefits Data layer decouples the rest of the app from any change in the datasources and in the entities. Domain layer can be a Java module!

Slide 135

Slide 135 text

Let’s add infinite layers of separation!!!

Slide 136

Slide 136 text

No content

Slide 137

Slide 137 text

Disadvantages Leads to Overengineering. Too much boilerplate code.

Slide 138

Slide 138 text

No content

Slide 139

Slide 139 text

Thanks @fernando_cejas @wendi_ @loganj @joenrv @macarse

Slide 140

Slide 140 text

Questions? #AndroidDevPro We are hiring! [email protected] Code: https://bit.ly/CleanAndroidRepo