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

Conductor - A Fragments Alternative

Conductor - A Fragments Alternative

In order to build truly encapsulated components, one need to use fragments to adhere to the proper lifecycle. There are many pain points when using Fragments. Conductor aims to bring view like simplicity with fragment like flexibility


Yousuf Haque

May 09, 2017

More Decks by Yousuf Haque

Other Decks in Programming


  1. Conductor The misunderstood use case for Fragments, and why Conductor

    fills it perfectly Yousuf Haque Twitter: @YousufHaque Github: yousuf-haque
  2. Nontrivial Apps Need Reusable Views - Reuse - Layouts -

    View Logic - Responsive UIs - Encapsulation - Loose coupling - Ease of testing - Sanity
  3. Reusing Views B.F.E. (Before Fragment Era) - <include> - Pros

    - Good for reusing layouts - Cons - Can’t reuse programmatically built views - Can’t reuse view logic - No lifecycle - Bottom Line - Great for reusing xml layouts that need neither lifecycles nor encapsulation - Not enough for “plug and play” components
  4. Reusing Views B.F.E. - Custom View Groups and Views -

    Pros - Good for reusing layouts, programmatic views, AND view logic - Lifecycle: onInflate, onAttachFromWindow, and onDetachFromWindow - Enough for “plug and play” components - Cons - Not enough lifecycle callbacks, need onStop/Start and onResume/Pause - GPS or Video playback - User status for a chat app - BYOBS: No backstack management - Bottom Line - Great for vast majority of use cases
  5. Surprise: Fragments!

  6. Arrival of Fragments: Pros - Fragments arrived in 3.0+ -

    Pros - Aimed to be like mini activity - Contain their own lifecycle methods to have composable UI components with rich, encapsulated lifecycle management - Fragments are less like reusable views, more like reusable lifecycles - Just add water Backstack management - Very much “plug and play” philosophy - Activity level convenience methods like onActivityResult, and onRequestPermissionResult
  7. - Hard to nest (correctly) - Key part of building

    view “atoms”/”plug and play” - Children fragments = shenanigans - Async Transactions - Hard to reason about view state at a given moment - commitPendingTransactions is virtually broken - Mostly fixed in sdk 24 and support lib 24.0 - commitNow - Children fragment guarantees - CommitNow transactions cannot modify backstack Arrival of Fragments: Cons
  8. - Views + library for backstack - Scoop - Flow

    - Pancakes - Simple-stack - Fine for simple lifecycles, still no support for start/stop and resume/pause - Need access to activity level items - Activity for result - Permission handling - Can solve with activities implementing interfaces - Increases coupling Fragment Alternatives
  9. - Basically a wholesale fragments replacement - Virtually the same

    API - Controllers = Fragments - onAttach, onDetach, onCreateView - Router = Fragment Manager - Router transactions = Fragment transactions - Has activity level lifecycle methods like activityStarted/Stopped and resumed/pause Enter Conductor
  10. - Built in backstack management - Has convenience methods like

    onActivityResult, and onRequestPermissionResult - Transactions are done synchronously - Controllers survive orientation changes - Separate bundles for saving view state on orientation change and controller state for process death - Composition by default - controllers embody the “plug and play” philosophy: compose small, simple controllers into more larger complex ones Enter Conductor (continued)
  11. None
  12. - Controller - “Atom” of the Conductor world - Has

    its own lifecycle, view, and router - Router - Applies router transactions - Manages backstack - RouterTransaction - Describes a mutation in UI state - A contoller, pushChangeHandler, popChangeHandler - A backstack consists of a list of routerTransactions - ChangeHandlers - Describes animation of controller entering or exiting UI - Fade, slide, etc Conductor API
  13. None
  14. None
  15. - popCurrentController() - pops the topmost controller - replaceTopController(transaction :

    RouterTransaction) - replaces the topmost controller with the given transaction - popToTag(tag : String) - pops all controllers from the top until the tagged controler and its transaction is reached - popToRoot() - pops all controllers until just the root is left - setRoot(transaction : RouterTransaction) - sets the given transaction as the root, and clears the back stack if any Key Router Methods
  16. - popController(controller: Controller) - removes given controller from that router’s

    backstack, leaving the rest of the backstack in tact - setRoot(transaction : RouterTransaction) - sets the given transaction as the root, and clears the back stack if any - setBackStack(transactionList : List<RouterTransaction>) - synthesizes a backstack for this router using the specified transactions Key Router Methods for Operating on the Backstack
  17. Why should I use Conductor over fragments? - Sync/Async -

    Async transactions have a higher surface area for bugs. Router transactions are sync - Transaction coupling - Fragment transactions couple the new fragment with its eventual container - Router transactions can be used by any router - Can move responsibility of building transaction elsewhere - Controllers are lightweight - everything can be a controller, even small views - Surgical backstack management - Smaller api + simpler lifecycle -> quicker mastery -> better features, faster - View like simplicity with fragment like power; fewer complexities/gotchas
  18. - Won’t it be more difficult to onboard new developers?

    - Simple api to begin with - Very similar to fragments - Very simple source code to go through - Demo app with tons of examples - *Conjecture* once the developer is ramped up, a pragmatic and productive API will help the team move faster Counterpoints
  19. - Not ‘blessed’ by Android Framework - "Once we have

    gotten in to this entry-point to your UI, we really don't care how you organize the flow inside. Make it all one activity with manual changes to its views, use fragments (a convenience framework we provide) or some other framework, or split it into additional internal activities. Or do all three as needed. As long as you are following the high-level contact of activity (it launches in the proper state, and saves/restores in the current state), it doesn't matter to the system." - Dianne Hackborn Pre IO ‘16 Google+ blog post - Fragments are a convenience, not a mandate - Conductor is built on views and the activity lifecycle (and a headless fragment) Counterpoints
  20. - https://github.com/bluelinelabs/Conductor - https://www.youtube.com/watch?v=k3IT-IJ0J98 - https://medium.com/square-corner-blog/advocating-against-android-fragm ents-81fd0b462c97 Resources