NOTE: I’ve deprecated Flowless (and have abandoned using Flow) in favor of what I wrote based on that from scratch: Simple-Stack . So you should keep in mind that I am no longer using this, because Simple-Stack solves quirks that I didn’t like about Flow’s design. In fact, this article probably isn’t even worth reading anymore. Read this one instead: https://medium.com/@Zhuinden/simplified-fragment-navigation-using-a-custom-backstack-552e06961257 — — — — — — — — — — — — — — — — — — — — — — — — — I’ve actually (and ), but it was rather bland. It’s time for a new and better article, a bit more straight to the point. I had also written about , but that should be considered obsolete — the architecture of Flow 1.0-alpha is much better and preferable (because it manages state persistence, while the previous version did not). written a previous article before about Flow Flowless using Flow 0.12 and Mortar The basics For those who haven’t been keeping track of just — well, nobody likes the lifecycle, and nobody likes how they work strangely with the CoordinatorLayout, and nobody likes how the FragmentManager transactions are a chaotic mess, and reading . how much Fragments have been hated for quite a while now the source code doesn’t really help So with that in mind, was created to take over what the FragmentManager intended to do — be a (like what gives you), make sure the views properly get restored on configuration change and process death; but the weird bugs that . Flow backstack addToBackStack(null) without nobody really understands Why would there be no such weird bugs, you ask? Because all transition from “ ” to “ ” is handled by — the user of Flow. State A State B you Some history, and what’s new Flow is actually quite old, although due to its lack of documentation and scary sample codes, it never really got adapted. There were . even articles about it (well, Square kinda left that hanging at Flow 0.8) In order to understand how has changed over time, let’s look at an example from that article for , and how we’d do the same thing with the latest Flow. Flow Flow 0.8 State representation Back in Flow 0.8, every view that was shown was described by an , where this object was annotated with . This screen contains the layout that should be shown when this object is set to the backstack. Object @Screen @Screen**( . . )** albumId**;** layout R = layout album_view public class AlbumScreen { private final int albumId**)** **} public AlbumScreen(int { this. ; albumId albumId = public int getAlbumId() {return albumId;}}** @Screen**( . . )** TrackScreen HasParent**< >** albumScreen**;** trackId**;** layout R = layout track_view public class implements AlbumScreen { private final AlbumScreen private final int albumScreen**, int** trackId**)** public TrackScreen(AlbumScreen { this. ; albumScreen albumScreen = this. ; trackId trackId = } @Override AlbumScreen getParent**()** albumScreen**;** public { return } AlbumScreen getAlbumScreen() { albumScreen;} public return int getTrackId() { trackId;}**}** public return This actually hasn’t changed much, other than that (and ) isn’t provided to you by the library anymore. You’re just told to use any Object, whatever Object you want; as long as it has and methods. @Screen HasParent equals() hashCode() Of course, it makes most sense for the key to still tell you what layout you’d like to build. It’s also easiest if you make your keys Parcelable (or provide a that can turn them into Parcelable, but that takes more effort). KeyParceler Without further ado, the way you’d do this now in Flow 1.0 is the following: You could also choose to provide the view’s layout identifier using an annotation if you want, you just need to also provide the logic that would extract the value from it. (Note: With current Flow 1.0-alpha, it might also be a good idea to extend _TreeKey_ instead of making a _HasParent_ annotation, if we want to make Flow handle “managed services” and reference counting — although I personally don’t use that, because I’ve had issues with it.) Navigation handling Back in Flow 0.8, you had to implement the interface, which gave you the new of objects (annotated with ), and the as to whether you went backward, forward or replace. Flow.Listener Backstack @Screen Direction @Override Direction direction**)** Object screen backstack**. (). ();**setContentView**( . (this,** screen**));** public void go( , Backstack backstack { = current getScreen Screens createView } This has changed a bit, because and no longer exist, and more importantly, Flow is no longer synchronous — it’s callback-based. This is to allow animations to be handled, and state change would be “committed” only once the animation is actually complete. And even more importantly, you also receive both the and the stack of objects. Screens @Screen previous new In Flow 1.0-alpha, you need to implement the interface (previously ), with the following signature: Dispatcher Flow.Dispatcher public interface Dispatcher {/*** Called when the history is about to change.* Note that Flow does not consider the Traversal to be finished,* and will not actually update the history,* until the callback is triggered.* Traversals cannot be canceled. * @param callback - Must be called to indicate completion of the traversal.*/ void dispatch(@NonNull Traversal traversal, @NonNull TraversalCallback callback); } Which, if we wanted to stay as simple as the article was, would look like this: As for the Context magic in the middle, . that’s exactly what [Screens](https://github.com/square/flow/blob/762864967765f0f3f7f9827609f5b97fdd963a76/flow/src/main/java/com/squareup/flow/Screens.java) used to do — — — — — — — — — — — — — — — — — — — — — — — — — — — — However, it’s worth noting that back in the day, did not handle viewstate persistence. You were entirely on your own in that regard. Now, Flow provides a class to which you can persist the state of your view, which is then stored into Flow’s very own stack. Flow State History With that in mind, we ought to create a view group that contains our view which we’re currently showing (which I’ll call ), so that we can easily access the view directly, and obtain/restore its state. root With that in mind, now not only do we have a backstack, but we also have state persistence for the views. Rotation and navigating away from our view won’t remove our viewstate anymore, and Flow handles most of the work internally. Neat! :) This is also where animating between the two views would be handled — for example, we could use if the exists. TransitionManager.beginDelayedTransition() previousView Switching between application states Remember this? FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.replace(R.id.fragment_container, FeedFragment.newInstance());fragmentTransaction.addToBackStack(null);fragmentTransaction.commit(); Well, back in Flow 0.8, it used to be this: flow**. (new** trackId**));** goTo Track( , albumScreen And now in Flow 1.0-alpha, it’s this: Flow.get(this).set( trackId**));** new Track( , albumScreen Using makes Flow check if the given key already exists (with ), and if it does, then it sets the state back to that view — and all views afterwards have their history cleared. If it doesn’t exist, then it’s a new state, and appends it to the end of the history stack. It’s essentially , except it actually works. That’s what determines the History stack you see in the traversal. set equals CLEAR_TOP destination If you want a bit more fine-grained history modifying, Flow gives you that as well: The scary stuff from the old versions: Mortar/Dagger The old Square “big picture” The examples for Flow 0.8 looked scary primarily because of Mortar and Dagger1. If you ask me, Mortar’s state persistence through the ViewPresenter was conceptually flawed, and Dagger1 is superceded by Dagger2. Still, it might be worth understanding to know what problems we’re trying to solve, even though it’s pretty much obsolete, or handled externally by the Dispatcher implementation. @Screen**( . . )**public class AlbumScreen final int albumId; layout R = layout album_view implements Blueprint { public AlbumScreen(int albumId) { this.albumId = albumId; } ** @Override String getMortarScopeName() {return "AlbumScreen";}** @Override Object getDaggerModule() {return new Module();} } @dagger.Module(addsTo = AppModule.class)static class Module {@Provides Album provideAlbum(JukeBox jukebox) {return jukebox.getAlbum(albumId);}} And afterwards, a Presenter is defined, which receives its dependencies injected from Dagger’s ObjectGraph, retained by Mortar’s scope: @Singletonpublic static class Presenter ViewPresenter**< >** Album album**;** extends AlbumView { private final @Inject Presenter**( )** **} Album album { this. ; album album = ** And the view: FrameLayout @Inject AlbumScreen**. ;** public class AlbumView extends { Presenter presenter TextView newNameView**;** private final AttributeSet attrs**)** attrs**);**Mortar**. ( ,** public AlbumView( , Context context { super( , context inject context this); Of course, this [_Blueprint_](https://github.com/square/mortar/pull/2/files#diff-8c45305219e23e9aa32a516d557a98e4) could have also been an annotation like _@Blueprint(scope = "AlbumScreen", module = AlbumScreen.Module.class)_ . Later, it was removed from Mortar as a library. What is Mortar? BluePrint was back before the , when Mortar was bundled with Dagger1 — it was essentially a service locator where a for the was identified by a String key, this survived configuration change, and , it used to provide the hierarchical scoping of dependencies (think and with Dagger2) and seeing them within the entire view hierarchy, while also preserving them between rotations. Mortar 0.17 API quake scope LinkedHashMap scope by overriding [getSystemService()](https://medium.com/@theMikhail/system-services-are-not-just-for-the-system-ce33aab4594a#.8ym79d4y0) @Singleton @ActivityScope Mortar also took upon itself to be a “Presenter” for the views (the ), and handle the delegation of from the Activity in order to persist the state of the presenter into the Activity’s Bundle. ViewPresenter<V> onSaveInstanceState() The problems of Mortar Mortar did NOT integrate with Flow at all — you navigated forward in Flow and navigated back; and Mortar could not persist the state of the view because it never received a callback from . All view state was lost between navigation changes. activity.onSaveInstanceState(Bundle) As a result, Mortar’s ViewPresenter was flawed for multiple reasons — and this is exactly why itself started handling state persistence. Flow Flow and state persistence (beyond viewstate) But Flow only provides a direct way to save viewstate — even though it has a slot in history that would allow saving a Bundle along with the view state. While Flow doesn’t provide a way (yet?) to access this Bundle, it’s possible to use this with some package-internal logic, with which you can save the presenter state through the view to a Bundle. manually And then you can call Now your View is also able to persist its state into a Bundle on rotation. Mortar as a service locator, and “ManagedServices” Mortar also provided a way to retrieve the Dagger object graph from the scope bound to the context, and the scope could be created and destroyed manually, independent from the Activity lifespan itself. This was replaced by Square’s Flow 1.0-alpha as the and , I personally don’t use these at all. They would solve the issue of creating and destroying services, and sharing them between view states if the keys belong to the same “flow”, thus sharing resources between the views. ManagedServices ServiceFactory If this worked it would be great, but I’ve run into cryptic bugs with the “node reference counting” and — so I skipped it. TreeKey But yes, the [ServiceFactory](https://github.com/square/flow/blob/master/flow-sample-tree/src/main/java/flow/sample/tree/FlowServices.java) is what would replace Mortar. The new big picture using Flow Now that we have a backstack with state persistence, we’re able to create views that represent our active window, rather than having to rely on Activities to do it. We also have fine-grained manipulation of this , rather than trying to make do what we want it to do with magical intent flags. backstack Android Our intents are replaced by key parameters, and fragment transactions are also replaced by the keys themselves. All state change is managed by the Dispatcher, which provides predictable behavior rather than having “unattached stale fragments”. Our Activities and our Fragments are replaced by Custom Viewgroups, eliminating complexity and providing better performance. With minimal configuration, we can now create view-driven applications, like so. Activity Key View Presenter Fairly simple separation between the view and presentation — cleaner than either Activity or Fragment. Why are we still fighting Fragments, when all we really need is a separate state representation that survives configuration changes? While you can use Conductor, I have not used it. I prefer the fine-grained control that Flow provides — and directly understanding what’s happening underneath. ( : ) Reddit discussion https://www.reddit.com/r/androiddev/comments/5awo5r/saying_no_to_fragments_and_activities_creating/