Mastering ViewPager with Directed Acyclic Graph

Muhammad Wajeeh
AndroidPub
Published in
4 min readJun 6, 2017

Edit: Checkout new NavigationArchitecture Component that was released recently.

Ever thought of using Directed Acyclic Graph (DAG) with ViewPager? Its a perfect combination.

Sample app

What is Directed Acyclic Graph?

DAG is just a graph where every edge goes forward i.e. there are no cycles.

source: wikipedia

Why use DAG?

ViewPager is the most commonly used view when dealing with flows. Almost every app has some sort of account creation or onboarding flow for new users. Or may be your app requires that user answers a few questions before you can create a specialized experience for them e.g. news or magazine apps. Or it could simply be that your app heavily relies on survey forms/questionnaires that your users fill to receive rewards.

One other simple and common use case for ViewPager is to show tabs which we are not interested in for this article.

If you want to create a truly dynamic flow which changes based on previous answers, as user fills out your form, then DAG is a must use data structure, otherwise your code will become unmanageable. If we let nodes in DAG to represent Fragment then you can easily see how flexible your ViewPager becomes. You can take any route during flow and can change next node based on previous answers. And it only needs to work in forward direction because, for reverse, ViewPager will just backtrack the steps.

DAG is so useful that I wonder why android does not support a DAGViewPagerAdapter natively!

Sample:

Before we start, we need an implementation of Directed Acyclic Graph. In Android, DAG is required when you are building ScriptGroup, as mentioned in ScriptGroup.Builder’s documentation. Another interesting place where DAG is being used is in CoordinatorLayout. For our implementation we will borrow it, as its not a public class.

Sample Directed Acyclic Graph

Here is how Node looks like:

PageDescriptor is required to instantiate our fragments as we are using cwac-pager adapter.NodeSelector is what we use to decide whether we want to move to this node or not. First we create all of our nodes with appropriate selectors, this process can be static or dynamic based on your requirements.

NodeSelector implementation to detect kids:

Once we have all the nodes, we can build our DAG:

Or you can roll your own fluent DAG Builder. Following is an example of a static flow that we have in one of our app:

For inspiration only (not included in sample)

Once your graph is ready, you can start your flow from root node by showing it:

From that point on whenever you want to go to next node, you ask DAG for all outgoing edges from current node and use the selector to pick appropriate node:

Handling Back Button

If the user goes back and changes his choice, we want to update the flow bundle and also remove that PageDescriptor from our adapter. We can’t do that as soon as back button is pressed because it will mess up back animation of ViewPager so instead we only cleanup our adapter lazily when going forward:

Now our flow can easily switch path based on answer

You can even combine several DAGs or handle complex scenarios where answer of 5th question invalidates answer of 3rd question, which 6th question was dependent on! Of course you can still use DAG if your flow is a simple straight line.

Next read:

Resources:

Another attempt at this by Santi Aguilera:

If you have a better way to implement this flow, share it in the comments or create a pull request. Feel free to ask any question and suggest topics which you think I should write on in the future.

--

--