Android navigation components: basic knowledge of Navgation usage details and source code interpretation

When the activity returns, it will carry data. We can get it directly from onActivityForResult

What do we need to do with navigation?

In fact, there are many methods to return data!
First:
Use the LiveData mode provided by the system;
The method is to get the LiveData of the last returned entry:
usage method:
BFragment setting data to A

 NavBackStackEntry upNav = navController.getBackStackEntry(R.id.fragmenta);
        upNav.getSavedStateHandle().getLiveData("data").setValue("hellow");

AFragment accepts data:

 NavBackStackEntry currentBackStackEntry = NavHostFragment.findNavController(this).getCurrentBackStackEntry();
        if(currentBackStackEntry!=null) {
            currentBackStackEntry.getSavedStateHandle().getLiveData("data","").observe(currentBackStackEntry, new Observer<String>() {
                @Override
                public void onChanged(String s) {
                    Log.e("data",s);
                }
            });
        }

We can see that the cores are NavBackEntry and SaveStateHandle respectively
Let's take a look at what these two classes do:
Look at NavBackEntry first
Navigation item class:
This class has navigation address information, NavDestination Context: Context and lifecycle owner
args parameters, viewmodelstore and savedstatehandle are provided
It seems that this is an abstraction of Fragment in the concept of navigation stack; You can also understand * * as our AFragment;

And NavBackEntry is from us

    @SuppressWarnings("WeakerAccess") /* synthetic access */
final Deque<NavBackStackEntry> mBackStack = new ArrayDeque<>();

Obtained from;

When NHF creates a View, it is our FCV; Yes, the View will be added to our parent View, and the NavController will be set to the tag of the parent View;

Here we are looking at how to get the Controller:


Let's look at the first one

 if (findFragment instanceof NavHostFragment) {
                return ((NavHostFragment) findFragment).getNavController();
            }

Let's not talk about this. NHF itself will be created;
The second getparentfragmentmanager Getprimarynavigationfragment is essentially the same as the previous one
The last one calls navigation find

     while (view != null) {
            NavController controller = getViewNavController(view);//Get from tag
            if (controller != null) {
                return controller;
            }
            ViewParent parent = view.getParent();
            view = parent instanceof View ? (View) parent : null;
        }
        return null;

Well, navController will not say;
Continue back to our NavBackStackEntry;

We can see what PopUpto means here?
In fact, it simply means to return to the specified stack when returning to the stack!
There is also an XML app corresponding to the attached parameter PopInclusive: popuptoinclusive = "true"

Let's look at this method first:

    if (mBackStack.isEmpty()) {
            // Nothing to pop if the back stack is empty
            return false;
        }
        ArrayList<Navigator<?>> popOperations = new ArrayList<>();
        Iterator<NavBackStackEntry> iterator = mBackStack.descendingIterator();
        boolean foundDestination = false;
        while (iterator.hasNext()) {
            NavDestination destination = iterator.next().getDestination();
            Navigator<?> navigator = mNavigatorProvider.getNavigator(
                    destination.getNavigatorName());
            if (inclusive || destination.getId() != destinationId) {
                popOperations.add(navigator);
            }
            if (destination.getId() == destinationId) {
                foundDestination = true;
                break;
            }
        }
        if (!foundDestination) {
            // We were passed a destinationId that doesn't exist on our back stack.
            // Better to ignore the popBackStack than accidentally popping the entire stack
            String destinationName = NavDestination.getDisplayName(mContext, destinationId);
            Log.i(TAG, "Ignoring popBackStack to destination " + destinationName
                    + " as it was not found on the current back stack");
            return false;
        }
        ------------------------------------------------------
        boolean popped = false;
        for (Navigator<?> navigator : popOperations) {
            if (navigator.popBackStack()) {
                NavBackStackEntry entry = mBackStack.removeLast();
                if (entry.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.CREATED)) {
                    entry.setMaxLifecycle(Lifecycle.State.DESTROYED);
                }
                if (mViewModel != null) {
                    mViewModel.clear(entry.mId);
                }
                popped = true;
            } else {
                // The pop did not complete successfully, so stop immediately
                break;
            }
        }
        updateOnBackPressedCallbackEnabled();
        return popped;

First explain one thing:
The concrete implementation of the Navigator abstract class is the implementation of fragmentnavigator activitynavigator and so on; There is an id stack and a frame manager
We can't just retreat the id stack in the NavController. The id stack is located in the navigator above
I draw the part under the dotted line, which means to withdraw from the stack!
The above part is to find and push to the specified stack. If inclusize is true, note that the specified stack will also be pushed!!! And back here to end!!!

Summarize the function of this field!!!
Suppose my stack is ab. when I navigate to C, I push to A. note that the process of C has not been implemented here; Then there is only AB in the stack
If I push to A, then b will be destroyed. If A exists, b will die. If inclusive=true, I'm sorry, there's nothing in the stack. Let's try:

A-B-C


So if I press return again, I will exit the app directly!

Well, this is episode knowledge;
Forgot to say... Here's a little knowledge. Look at the source code. It's too fast. It's also the navigator method before calling this navigator
It is mainly used for parameter merging! But we found such a piece of code

When the target id is 0, we can also return the stack!!!
We know that the method naviUp is used when returning

See, this is actually a return stack method called!!! So when we navigate to the destination, if the destination of the action is not written, is it
OK, go back to the original place:

Start replacing... I won't read the previous introduction here

This means that if the current is not a FloatWindow but the last is, you need to remove the floatwide from the stack! That is, we understand dialogfragment in this way first. We didn't read FloatWindow carefully, but found that the goal of dialogfragment has been achieved

This code is more interesting!
First, you can think of NavGraph as an xml, that is

Such an xml is different without other important things;

   final SparseArrayCompat<NavDestination> mNodes = new SparseArrayCompat<>();
    private int mStartDestId;
    private String mStartDestIdName;

It is our starting navigation position and our navigation destination set, which can be regarded as a root! More vividly

The concept of NavGraph is introduced above,
Let's continue to introduce the rest of the navigation method:

            if (node instanceof NavGraph) {
                do {
                    NavGraph parent = destination.getParent();
                    if (parent != null) {
                        NavBackStackEntry entry = new NavBackStackEntry(mContext, parent,
                                finalArgs, mLifecycleOwner, mViewModel);
                        hierarchy.addFirst(entry);
                        // Pop any orphaned copy of that navigation graph off the back stack
                        if (!mBackStack.isEmpty()
                                && mBackStack.getLast().getDestination() == parent) {
                            popBackStackInternal(parent.getId(), true);
                        }
                    }
                    destination = parent;
                } while (destination != null && destination != node);
            }

When we start the App to load graph - > (aframent), it will enter the stack
Here we need to take a look at the dowhile loop, focusing on mbackstack getLast(). getDestination() == parent
What do you mean? The last destination currently occupied is the same as the parent of our current destination!

Let's study the parent, otherwise it will be very confused

I went straight into the loading place

Here, the provider calls NavGraphNavigator

  final NavDestination dest = navigator.createDestination();

        dest.onInflate(mContext, attrs);

It is very simple to create a NavGraph. The key point is the onInflate method

Set our start destination and our start destination id name, and NavGraph inherits from NavDestination
Here is super Oninflate is as follows

We did not find that the parent of the current NavGraph is set

We found that only in addDestination can we set the parent

We might as well assume that the current entry is our NavGraph. Then, if an include appears in the second entry and a Graph is made
So the include undoubtedly points to a NavGraph

Here's an explanation: different navgraph s cannot have the same id

The root IDs of these two files cannot be the same, and no errors can be detected during compilation

Obviously, the meaning of this sentence is obvious. If it already exists, it will not be put in. When we include two of the same

I'm sorry... The two include in xml will not be return ed here... Because it was said that navGraph is new
Then the only possibility is that our code dynamically adds the same NavGraph twice


Here we can set the parent!!
Then I'm very confused!
The parent of our root navGraph is null
Here comes the problem!!!


When loading for the first time, the parent here is not null!!!

In fact, this is my problem!!! I didn't quite understand here because I initially ignored a key class
That is, our Node is our root, and NavGraph is indeed null
however

Changes have taken place here! What I didn't figure out at the beginning is that I thought the Navigator to navigate to the destination should be frament Navigator
!!!
However, if it is NavGraph, it must be NavGraph navigator. This class has been ignored by me!!!

That is, the initial navigator has experienced conversion!!!
That is, our newDest should be Destination instead of NavGraph at the moment
And NavGraph will not exist in our real stack!!!
I won't introduce it later. It's very simple. It's the operation before a meal on the stack!!!

Let's continue to learn about NavBackStateEntry and the return data
Each NavBackStateEntry holds an mSavedStateHandle;
Let's look at this creation method first

Here we also introduce ViewmodelProvide:
Nothing special: hold a ViewmodelStroe, and the ViewModel is an HshMap
So get is to create and save it if you can't get it!!!
The back is very simple!!! It's no different from our use of LiveData

Keywords: Android

Added by ultk on Tue, 28 Dec 2021 01:37:42 +0200