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

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.

Steve Zeidner

August 25, 2016
Tweet

More Decks by Steve Zeidner

Other Decks in Programming

Transcript

  1. 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.”
  2. FRAGMENT PROBLEMS • Lifecycle • Fragment Backstack • Tightly coupled

    View / Controller logic • Default constructor • Memory management + Fragment bugs
  3. public static MyFragment newInstance(int index) { MyFragment f = new

    MyFragment(); Bundle args = new Bundle(); args.putInt("index", index); f.setArguments(args); return f; }
  4. public final class TrackScreen { public final String albumId; public

    final String trackId; public TrackScreen(String albumId, String trackId) { this.albumId = albumId; this.trackId = trackId; } }
  5. FLOW • Navigate between screens • Manages history and persists

    state • Subflows - nested flows • Dispatcher - executes state changes
  6. @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); } }
  7. 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); } }
  8. 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); } }
  9. @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); } } }
  10. Flow tells the app where to go while Mortar informs

    it of what to build and how long to live.
  11. MORTAR & FLOW ADVANTAGES • MVP pattern • Memory efficient

    views • No Fragment issues! • Easier Dependency Injection
  12. MORTAR & FLOW DOWNSIDES • Steep learning curve • No

    Material style animations • It's not the Google way
  13. RESOURCES • [Lukas Piliszczuk] (https://github.com/lukaspili) • Flow Navigation • Mortar

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