Simplify Android UI

Simplify Android UI

The introduction of Fragments in Android gave developers a tool to create more modular Android user interfaces. With the added functionality, however, a host of complexities and bugs were introduced that have still not been resolved years later. In this talk, you’ll learn the reasons to use a view-based architecture, how to construct a view only interface using Mortar and Flow, and lessons learned when moving away from a fragment­-oriented UI.

5e3e6f0c073e2d18f6c4716d83c6cea3?s=128

Steve Zeidner

August 25, 2016
Tweet

Transcript

  1. 2.
  2. 3.
  3. 4.
  4. 5.
  5. 7.

    ACTIVITY “An activity represents a single screen with a user

    interface. For example, an email app might have one activity that shows a list of new emails, another activity to compose an email, and another activity for reading emails. Although the activities work together to form a cohesive user experience in the email app, each one is independent of the others.”
  6. 8.
  7. 9.
  8. 10.

    FRAGMENT PROBLEMS • Lifecycle • Fragment Backstack • Tightly coupled

    View / Controller logic • Default constructor • Memory management + Fragment bugs
  9. 11.

    public static MyFragment newInstance(int index) { MyFragment f = new

    MyFragment(); Bundle args = new Bundle(); args.putInt("index", index); f.setArguments(args); return f; }
  10. 12.
  11. 13.
  12. 14.
  13. 15.
  14. 16.
  15. 17.

    public final class TrackScreen { public final String albumId; public

    final String trackId; public TrackScreen(String albumId, String trackId) { this.albumId = albumId; this.trackId = trackId; } }
  16. 20.

    FLOW • Navigate between screens • Manages history and persists

    state • Subflows - nested flows • Dispatcher - executes state changes
  17. 21.
  18. 22.

    @dagger.Component(dependencies = MainActivity.Component.class) @DaggerScope(Component.class) public interface Component extends AppDependencies {

    void inject(TrackView view); } @DaggerScope(Component.class) public static class Presenter extends ViewPresenter<TrackView> { @Override protected void onLoad(Bundle savedInstanceState) { getView().albumTitle.setText("Chalk Dust Torture"); } @Override protected void onSave(Bundle outState) { super.onSave(outState); } }
  19. 23.

    public class TrackView extends FrameLayout { @Bind(R.id.album_title) public TextView albumTitle;

    @Inject protected TrackScreen.Presenter presenter; public TrackView(Context context, AttributeSet attrs) { super(context, attrs); DaggerService.<TrackScreen.Component>getDaggerComponent(context).inject(this); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); presenter.takeView(this); } @Override protected void onDetachedFromWindow() { presenter.dropView(this); super.onDetachedFromWindow(); } @Override protected void onFinishInflate() { super.onFinishInflate(); ButterKnife.bind(this); } }
  20. 26.

    public class TrackView extends FrameLayout { @Bind(R.id.album_title) public TextView albumTitle;

    @Inject protected TrackScreen.Presenter presenter; public TrackView(Context context, AttributeSet attrs) { super(context, attrs); DaggerService.<TrackScreen.Component>getDaggerComponent(context).inject(this); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); presenter.takeView(this); } @Override protected void onDetachedFromWindow() { presenter.dropView(this); super.onDetachedFromWindow(); } @Override protected void onFinishInflate() { super.onFinishInflate(); ButterKnife.bind(this); } }
  21. 28.
  22. 29.

    @Layout(R.layout.screen_track) public class TrackScreen extends Path implements ScreenComponentFactory<MainActivity.Component> { public

    final String albumId; public final String trackId; public TrackScreen(String albumId, String trackId) { this.albumId = albumId; this.trackId = trackId; } @Override public Object createComponent(MainActivity.Component parent) { return DaggerPostScreen_Component.builder() .component(parent) .build(); } @dagger.Component(dependencies = MainActivity.Component.class) @DaggerScope(Component.class) public interface Component extends AppDependencies { void inject(TrackView view); } @DaggerScope(Component.class) public static class Presenter extends ViewPresenter<TrackView> { @Override protected void onLoad(Bundle savedInstanceState) { getView().albumTitle.setText("Chalk Dust Torture"); } @Override protected void onSave(Bundle outState) { super.onSave(outState); } } }
  23. 30.

    Flow tells the app where to go while Mortar informs

    it of what to build and how long to live.
  24. 31.
  25. 32.
  26. 34.

    MORTAR & FLOW ADVANTAGES • MVP pattern • Memory efficient

    views • No Fragment issues! • Easier Dependency Injection
  27. 35.

    MORTAR & FLOW DOWNSIDES • Steep learning curve • No

    Material style animations • It's not the Google way
  28. 38.

    RESOURCES • [Lukas Piliszczuk] (https://github.com/lukaspili) • Flow Navigation • Mortar

    Architect
 • [CabinLife] (https://github.com/szeidner/cabinlife-android)