I'm experimenting with the Navigation Component an...
# android
t
I'm experimenting with the Navigation Component and I'm trying to figure out what's the proper/intended api usage. Imagine I'm building a Slack clone with the following nav graph:
Copy code
WorkspacesListFragment                     WorkspaceFragment                    ThreadFragment
            R.id.workspacesListFr                      R.id.workspaceFr                     R.id.threadFr
            +--------------------+                    +-----------------+                 +----------------+
            |                    |                    |                 |                 |                |
            |  List:             |  arg: workspaceId  |  List:          |  arg: threadId  |                |
            |  * kotlinlang      +-------------------->  * androidx     +----------------->                |
 start dest |  * workflow-kotlin |                    |  * compose      |                 |                |
+----------->  * etc...          |                    |  * etc...       |                 |                |
            |                    |                    |                 |                 |                |
            |                    |                    |                 |                 |                |
            |                    |                    |                 |                 |                |
            +------+-------------+                    +-----------------+                 +----------------+
                   |
                   |
                   |
                   |
                   |          CreateWorkspaceFragment
                   |
                   |        +--------------------------+
                   |        |                          |
                   |        | besides a new workspace, |
                   |        | optionally could create  |
                   +--------> a new thread as well     |
                            |                          |
                            |   has workspaceId        |
                            |   has threadId?          |
                            |                          |
                            |                          |
                            |                          |
                            +--------------------------+
When a new workspace is created I'd like to navigate to it when the operation is successful. I've come up with 2 ideas: Option 1: use the navigation controller available inside CreateWorkspaceFragment and navigate directly from there:
Copy code
CreateWorkspaceFragment {
    ...
    fun onComplete(workspaceId: String, threadId: String?) {
        val navController = findNavController()
        // 1. Go back to WorkspacesListFragment
        // fragment will trigger an async api call to fetch and then display the list
        navController.popBackStack()

        // 2. Go to WorkspaceFragment
        // fragment will trigger an async api call to fetch and then display the workspace
        navController.navigate(
            WorkspacesListFragmentDirections.actionToWorkspace(workspaceId)
        )

        // 3. Go to ThreadFragment if user created a thread
        // fragment will trigger an async api call to fetch and then display the thread
        if (threadId.isNullOrEmpty().not()){
            navController.navigate(
                WorkspaceFragmentDirections.actionToThread(threadId!!)
            )
        }
    }
}
Option 2: • return workspaceId & threadId as a result to the previous
WorkspacesListFragment
Destination (either FragmentResult API or navController.previousBackStackEntry?.savedStateHandle ) • from
WorkspacesListFragment
I can navigate to
WorkspaceFragment
and pass along workspaceId & threadId • inside
WorkspaceFragment.onCreate
I can check the args and if there's a threadId I'll trigger navigation from there to
ThreadFragment
(but I'll have to
WorkspaceFragment.arguments = null
, otherwise when coming back it'll navigate to
ThreadFragment
again, indefinitely) Essentially, Option 1 come down to handling my navigation logic in-place and Option 2 would spread it across each destination. FragmentNavigator does Fragment transactions asynchronously, Option 1 acts like navigation is a synchronous operation and it doesn't seem right to me... but Option 2 is a lot more code, so... Suggestions? (anyone from the androidx.navigation team around here?)
i
navigate()
is a synchronous operation (even if the fragment operations aren't), so just call
navigate()
and
popBackStack()
as you want. That's exactly how deep linking works FWIW
Although you probably want your action to use
popUpTo
to pop your create fragment on the way to the destination instead of manually calling
popBackStack()
as that will avoid a dispatch to any
OnDestinationChangedListener
and make it a single atomic operation
t
I don't see an obvious way to have a single atomic operation from Create straight to Workspace or Thread? (I'd like to have the backstack populated as I travel from Create to Thread, so going back from Thread would be just popping destinations)
i
Did you have a question about
popUpTo
that the docs don't cover? https://developer.android.com/guide/navigation/navigation-navigate#pop
If your back stack is
WorkspacesListFragment
->
CreateWorkspaceFragment
and want to be at a back stack of
WorkspacesListFragment
->
WorkspaceFragment
, then you want to
popUpTo
CreateWorkspaceFragment
with
popUpToInclusive="true"
and a destination of
WorkspaceFragment
While you can use
popUpTo
to pop multiple destinations before you navigate to your new destination, you can only add one destination to the back stack at a time, so if you wanted to go all the way to
ThreadFragment
, you'd have to do a separate
navigate()
afterward with
WorkspaceFragmentDirections.actionToThread()
as you are doing, yes.
t
currently I don't have an action from CreateWorkspaceFragment to WorkspacesListFragment. I'm going back to WorkspacesListFragment by popping Create. does it make a difference if I add an action from CreateWorkspacesFragment to WorkspacesListFragment and popUpTo to pop Create?
i
that will avoid a dispatch to any 
OnDestinationChangedListener
 and make it a single atomic operation
Personally, I'd definitely add the action there, just to make it entirely clear on where you go after the
CreateWorkspaceFragment
t
but I'll still have 3
.navigate()
calls if I want to reach Thread from Create, right?
Copy code
// 1. Go back to WorkspacesListFragment
navController.navigate(
    CreateWorkspaceFragmentDirections.actionBackToWorkspaceList()
)
// 2. Go to WorkspaceFragment
navController.navigate(
    WorkspacesListFragmentDirections.actionToWorkspace(workspaceId)
)
// 3. Go to ThreadFragment
navController.navigate(
    WorkspaceFragmentDirections.actionToThread(threadId!!)
)
i
Just two, since you can
popUpTo
as part of the move to the WorkspaceFragment:
Copy code
// 1. Go to WorkspaceFragment, popping create on the way out by adding a popUpTo to this action
navController.navigate(
    CreateWorkspaceFragmentDirections.actionToWorkspace(workspaceId)
)
// 2. Go to ThreadFragment
navController.navigate(
    WorkspaceFragmentDirections.actionToThread(threadId!!)
)
t
oh right. the action would have the destination set to WorkspaceFragment, not WorkspacesListFragment
@Ian Lake managed to get something going. thanks so much for your help and very quick responses! 🍻
🎉 1