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

AndroidDevLikeAProDroidconSF

rallat
March 18, 2016

 AndroidDevLikeAProDroidconSF

rallat

March 18, 2016
Tweet

More Decks by rallat

Other Decks in Programming

Transcript

  1. public interface ImageLoader { void load(ImageView view, String url); void

    loadWithTransformation(ImageView view, String url, Transformation transformation); }
  2. 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); } }
  3. 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); } }
  4. 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(); }
  5. 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(); }
  6. 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(); }
  7. 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(); }
  8. 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(); }
  9. 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<Image> images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }
  10. 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<Image> images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }
  11. 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<Image> images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }
  12. 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<Image> images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }
  13. 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<Image> images) { adapter = new ImageRecyclerView(images); recyclerView.setAdapter(adapter); } @Override public void logout() { TwitterCore.getInstance().logOut(); finish(); startActivity(new Intent(this, LoginActivity.class)); } ... }
  14. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  15. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  16. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  17. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  18. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  19. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  20. public class TopImagesListPresenterImpl implements TopImagesListPresenter { private final ImageListModel model;

    private TopImagesListView view; private List<Image> 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); } } } … }
  21. public class TopImagesListPresenterImpl implements TopImagesListPresenter { … private static class

    WeakCallback extends Callback<List<Image>> { private WeakReference<TopImagesListView> view; private List<Image> imagesList; … @Override public void success(Result<List<Image>> 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(); } } } … }
  22. public class TopImagesListPresenterImpl implements TopImagesListPresenter { … private static class

    WeakCallback extends Callback<List<Image>> { private WeakReference<TopImagesListView> view; private List<Image> imagesList; … @Override public void success(Result<List<Image>> 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(); } } } … }
  23. public class TopImagesListPresenterImpl implements TopImagesListPresenter { … private static class

    WeakCallback extends Callback<List<Image>> { private WeakReference<TopImagesListView> view; private List<Image> imagesList; … @Override public void success(Result<List<Image>> 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(); } } } … }
  24. public class TopImageListModelImpl implements TopImageListModel { private final CustomApiClient client;

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

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

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

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

    ... @Override public void getMostRtImages(final Callback<List<Image>> callback) { client.getTimelineService().homeTimeline(200, true, true, true, true, new Callback<List<Tweet>>() { @Override public void success(Result<List<Tweet>> result) { final List<Image> items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }
  29. 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.
  30. 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.
  31. MVP Pros Increases separation of concerns in 3 layers: Passive

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

    View - Render logic Presenter - Handle User events Model - Business logic
  33. MVP Cons BoilerPlate to wire the layers. Model can’t be

    reused since is too tied to the specific use case.
  34. 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.
  35. public class EffectiveAndroidApplication extends Application { Map<Class, Presenter> presenterHolder; …

    public void putPresenter(Class c, Presenter p) { presenterHolder.put(c, p); } public <T extends Presenter> T getPresenter(Class<T> c) { return (T) presenterHolder.get(c); } public void remove(Class c) { presenterMap.remove(c); } }
  36. public class PresenterHolder { static volatile PresenterHolder singleton = null;

    private Map<Class, Presenter> presenterMap; … public void putPresenter(Class c, Presenter p) { singleton.put(c, p); } public <T extends Presenter> T getPresenter(Class<T> c) { return (T) singleton.get(c); } public void remove(Class c) { presenterMap.remove(c); } }
  37. 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); } } }
  38. 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); } } }
  39. 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); } } }
  40. 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); } } }
  41. 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); } } }
  42. View Presenter Repository Presentation Layer Domain Layer Interactor Entity Entity

    Entity Interactor Interactor Data Layer ViewEntity User Interaction
  43. public class GetTopArticlesImpl implements GetTopArticles { private final TweetRepository tweetRepository;

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

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

    … @Override public void execute(final Callback<List<Article>> callback) { tweetRepository.getTimeline(new Callback<List<Tweet>>() { @Override public void success(Result<List<Tweet>> result) { final List<Article> items = processTweets(result); callback.success(items, null); } @Override public void failure(TwitterException e) { callback.failure(e); } }); } }
  46. public class TweetRepositoryImpl implements TweetRepository { private final TwitterApiClient client;

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

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

    private final TweetCache cache; private final TweetDB db; ... @Override public void getTimeline(final Callback<List<Tweet>> 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); } } }
  49. View Presenter Repository Presentation Layer Domain Layer Interactor Entity Entity

    Entity Interactor Interactor Data Layer ViewEntity User Interaction
  50. Clean Architecture Benefits Data layer decouples the rest of the

    app from any change in the datasources and in the entities.