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. SIMPLIFY ANDROID UI
    Steve Zeidner
    @stevezeidner

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. APPLICATION COMPONENTS
    • Activities
    • Services
    • Content Providers
    • Broadcast Receivers

    View Slide

  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.”

    View Slide

  8. View Slide

  9. View Slide

  10. FRAGMENT PROBLEMS
    • Lifecycle
    • Fragment Backstack
    • Tightly coupled View / Controller logic
    • Default constructor
    • Memory management + Fragment bugs

    View Slide

  11. public static MyFragment newInstance(int index) {
    MyFragment f = new MyFragment();
    Bundle args = new Bundle();
    args.putInt("index", index);
    f.setArguments(args);
    return f;
    }

    View Slide

  12. View Slide

  13. View Slide

  14. View Slide

  15. View Slide

  16. FLOW

    View Slide

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

    View Slide

  18. flow.set(new TrackScreen(albumId, trackId))

    View Slide

  19. flow.goBack();

    View Slide

  20. FLOW
    • Navigate between screens
    • Manages history and persists state
    • Subflows - nested flows
    • Dispatcher - executes state changes

    View Slide

  21. MORTAR

    View Slide

  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 {
    @Override
    protected void onLoad(Bundle savedInstanceState) {
    getView().albumTitle.setText("Chalk Dust Torture");
    }
    @Override
    protected void onSave(Bundle outState) {
    super.onSave(outState);
    }
    }

    View Slide

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

    View Slide

  24. onEnterScope(MortarScope scope)
    onLoad(Bundle savedInstanceState)
    dropView()
    onSave(Bundle outState)
    onExitScope()

    View Slide

  25. SCOPING AND
    DEPENDENCY INJECTION

    View Slide

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

    View Slide

  27. "Don't call us, we'll call you."

    View Slide

  28. View Slide

  29. @Layout(R.layout.screen_track)
    public class TrackScreen extends Path implements ScreenComponentFactory {
    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 {
    @Override
    protected void onLoad(Bundle savedInstanceState) {
    getView().albumTitle.setText("Chalk Dust Torture");
    }
    @Override
    protected void onSave(Bundle outState) {
    super.onSave(outState);
    }
    }
    }

    View Slide

  30. Flow tells the app where to go while Mortar informs
    it of what to build and how long to live.

    View Slide

  31. View Slide

  32. View Slide

  33. CABINLIFE DEMO

    View Slide

  34. MORTAR & FLOW ADVANTAGES
    • MVP pattern
    • Memory efficient views
    • No Fragment issues!
    • Easier Dependency Injection

    View Slide

  35. MORTAR & FLOW DOWNSIDES
    • Steep learning curve
    • No Material style animations
    • It's not the Google way

    View Slide

  36. Should you convert an existing app?

    View Slide

  37. It depends.

    View Slide

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

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

    View Slide

  39. QUESTIONS?

    View Slide