Jetpack之Navgation和Fragment

一、简述

Jetpack中的Navgation和SystemUI中的NavgationBar导航栏并不是一个东西。在Jetpack中的Navgation是为了适配Fragment而诞生的,在当今Android开发中,Fragment的优点在于轻量、可控制性强,但其相较与Activity而言,仍然有着其弊端,如:Activity的回退栈以及页面的参数传递。此时Navgation正是为了适配Fragment开发而推出的。此篇仅仅简单介绍Navgation的使用,原理下篇叙述。

二、Navgation介绍

2.1 Navgation三大件:

1、导航图:用于指明从源页面跳转的页面或者目的地。
2、NavHost:显示导航图中目标的空白容器。导航组件包含一个默认 NavHost 实现 (NavHostFragment),可显示Fragment 目标,说白了就是存放Fragment等控件的容器。
3、NavController:在 NavHost 中管理应用导航的对象。当用户在整个应用中移动时,NavController 会安排NavHost 中目标内容的交换。

2.2 优点

   处理 Fragment 事务。
   默认情况下,正确处理往返操作。
   为动画和转换提供标准化资源。
   实现和处理深层链接。
   包括导航界面模式(例如抽屉式导航栏和底部导航),用户只需完成极少的额外工作。
   Safe Args - 可在目标之间导航和传递数据时提供类型安全的 Gradle 插件。
   ViewModel 支持 - 您可以将 ViewModel 的范围限定为导航图,以在图表的目标之间共享与界面相关的数据。

2.3 使用Navgation

(1)导入Navgation依赖

    def nav_version = "2.3.0"
    // Java language implementation
    implementation "androidx.navigation:navigation-fragment:$nav_version"
    implementation "androidx.navigation:navigation-ui:$nav_version"

(2)创建导航图
在这里插入图片描述
在这里插入图片描述
这里必须要声明app:startDestination属性指明首次启动时加载的Fragment
Action标签指明跳转的目的地,也可以在fragment中声明Action,但仅此表示从fragmentX ----> fragmentY;
若像下列在fragment外定义action标签,则便是任意fragment都可以跳转到该action中的destination。

注意:并非只能声明fragment标签,也可以是activity、dialog控件。
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/fragment_a">

    <action
        android:id="@+id/to_fragmenta"
        app:destination="@+id/fragment_a"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim">
    </action>
    <action
        android:id="@+id/to_fragmentb"
        app:destination="@+id/fragment_b"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim">
    </action>
    <action
        android:id="@+id/to_fragmentc"
        app:destination="@+id/fragment_c"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim">
    </action>
    <action
        android:id="@+id/to_fragmentd"
        app:destination="@+id/fragment_d"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim">
    </action>
    <action
        android:id="@+id/to_fragmente"
        app:destination="@+id/fragment_e"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim">
    </action>

    <fragment
        android:id="@+id/fragment_a"
        android:name="com.example.navigatinandfragment.FragmentA"
        android:label="bfragment"
        tools:layout="@layout/fragment_a">
    </fragment>
    <fragment
        android:id="@+id/fragment_b"
        android:name="com.example.navigatinandfragment.FragmentA"
        android:label="cfragment"
        tools:layout="@layout/fragment_b">
        <!--为destination提供深层链接技术-->
        <deepLink app:uri="www.YourWebsite.com/{
    
    mn_params}"/>
    </fragment>
    <fragment
        android:id="@+id/fragment_c"
        android:name="com.example.navigatinandfragment.FragmentA"
        android:label="dfragment"
        tools:layout="@layout/fragment_c">
    </fragment>
    <fragment
        android:id="@+id/fragment_d"
        android:name="com.example.navigatinandfragment.FragmentA"
        android:label="dfragment"
        tools:layout="@layout/fragment_d">
    </fragment>
    <fragment
        android:id="@+id/fragment_e"
        android:name="com.example.navigatinandfragment.FragmentA"
        android:label="efragment"
        tools:layout="@layout/fragment_e">
    </fragment>

</navigation>

(3)声明NavHost,app:defaultNavHost="true"属性很关键,功能是让fragment拦截back按键,实现回退栈

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/fragment_nav"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true"/>
    <!--让fragment拦截back按键,实现回退栈-->
    
<!--Activity的底部导航栏,同微信界面中底部导航栏-->
   <com.google.android.material.bottomnavigation.BottomNavigationView
        android:layout_height="50dp"
        android:layout_width="match_parent"
        android:id="@+id/buttom"
        android:background="@android:color/white"
        android:layout_alignParentBottom="true"
        app:itemIconTint="@drawable/select"
        app:itemTextColor="@drawable/select"
        app:menu="@menu/meni"
        app:labelVisibilityMode="labeled">
<!--此属性是为了防止导航栏Item超过3个时不显示title-->
    </com.google.android.material.bottomnavigation.BottomNavigationView>

(4)创建NavController,绑定NavGraph和底部导航栏

public class MainActivity extends AppCompatActivity {
    
    
    BottomNavigationView bottom;
    NavController navController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bottom = findViewById(R.id.buttom);
        navController = Navigation.findNavController(this,R.id.fragment_nav);
        //NavigationUI类  是用来对AppBar和navController进行绑定
        NavigationUI.setupWithNavController(bottom,navController);
    }
//        button.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    
    
//            @Override
//            public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
    
    
//                switch (menuItem.getItemId()){
    
    
//                    case R.id.bfragment:
//                        navController.navigate(
//                                R.id.to_bfragment);
//                        break;
//                    case R.id.cfragment:
//                        navController.navigate(
//                                R.id.to_cfragment);
//                        break;
//                    case R.id.dfragment:
//                        navController.navigate(
//                                R.id.to_dfragment);
//                        break;
//                    case R.id.efragment:
//                        navController.navigate(
//                                R.id.to_efragment);
//                        break;
//                    case R.id.afragment:
//                        navController.navigate(
//                                R.id.to_afragment);
//                        break;
//                }
//
//                return true;
//            }
//        });
}

(5)Fragment之间传递数据、实现深度链接技术

public class FragmentA extends Fragment {
    
    
    Button button;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    
    
        return inflater.inflate(R.layout.fragment_a,container);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    
    
        super.onViewCreated(view, savedInstanceState);
        button = view.findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                sendNotifacation();
            }
        });
    }

    private void sendNotifacation() {
    
    
        if(getActivity() == null){
    
    
            return;
        }
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
    
    
            NotificationManager manager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel notificationChannel = new NotificationChannel("1","Channel_name",NotificationManager.IMPORTANCE_HIGH);
            notificationChannel.setDescription("desc");
            manager.createNotificationChannel(notificationChannel);
        }

        NotificationCompat.Builder notification = new NotificationCompat.Builder(getActivity(),"1")
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("Navigation_And_Fragment")
                .setContentText("Hello World!")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(getPendingIntent())
                .setAutoCancel(true);

        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(getActivity());
        notificationManagerCompat.notify(8,notification.build());
    }

    //通过PendingIntent设置,当通知被点击后需要跳转到哪个destination,以及传递的参数
    private PendingIntent getPendingIntent() {
    
    
        if(getActivity() != null)
        {
    
    
            Bundle bundle = new Bundle();
            bundle.putString("params", "from Notification");
            return Navigation
                    .findNavController(getActivity(), R.id.fragment_nav)
                    .createDeepLink()
                    .setGraph(R.navigation.nav_graph)
                    //目的地Frgment
                    .setDestination(R.id.fragment_b)
                    .setArguments(bundle)
                    .createPendingIntent();
        }
        return null;
    }
}

三、Navgation源码解析

上面介绍到Navgation有三大件:NavGraph、NavHostFragment、NavController,NavHostFragment作为NavGraph中destination的容器,而NavController则是负责调度NavGraph和NavHostFragment的。
带着疑问看源码才会记得比较深刻,先来看看NavHostFragment。

  1. NavController是什么时候被创建出来的?

先截取NavHostFragment的onCreate代码,从下面代码可以看出,NavHostFragment是Fragment的一个子类,并且实现了NavHost接口。当NavHostFragment中的Fragment被创建出来之后,回调onCreate方法。

@Navigator.Name("fragment")
public class NavHostFragment extends Fragment implements NavHost {
    
     
@CallSuper
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        final Context context = requireContext();
        //创建了NavController对象
        mNavController = new NavHostController(context);
        //初始化了NavController的一些参数
        mNavController.setLifecycleOwner(this);
        mNavController.setOnBackPressedDispatcher(requireActivity().getOnBackPressedDispatcher());
        // Set the default state - this will be updated whenever
        // onPrimaryNavigationFragmentCh栈anged() is called
        //关键:确保回退栈
        mNavController.enableOnBackPressed(
                mIsPrimaryBeforeOnCreate != null && mIsPrimaryBeforeOnCreate);
        mIsPrimaryBeforeOnCreate = null;
        mNavController.setViewModelStore(getViewModelStore());
        //这里看到将NavControoler传入了
        onCreateNavController(mNavController);

在这里看到创建了DialogFragment和FragmentNavgation两个对象,并且将其放到了NavigatorProvider的HashMap中。

@CallSuper
    protected void onCreateNavController(@NonNull NavController navController) {
    
    
        navController.getNavigatorProvider().addNavigator(
                new DialogFragmentNavigator(requireContext(), getChildFragmentManager()));
        navController.getNavigatorProvider().addNavigator(createFragmentNavigator());
    }

NavigatorProvider中的HashMap

private final HashMap<String, Navigator<? extends NavDestination>> mNavigators = new HashMap<>();
@Nullable
public final Navigator<? extends NavDestination> addNavigator(
            @NonNull Navigator<? extends NavDestination> navigator) {
    
    
        String name = getNameForNavigator(navigator.getClass());

        return addNavigator(name, navigator);
}

在回到onCreate方法中,看看mNavController初始化的时候做了什么,继续跟踪NavHostController父类的构造方法

 public NavHostController(@NonNull Context context) {
    
    
        super(context);
   }

**总结一:**看到这里我们明白了,在NavHostFragment被创建出来调用onCreate的时候,创建了NavControll,以及将NavGraphNavigator、ActivityNavigator、FragmentNovigator和DialogNovigator创建了,并且将这四个容器放大了NavigatorProvidrer的HashMap中保存起来了,Key值是每个Navigator类上注解中的值,如@Navigator.Name(“fragment”)。因此可以知道在导航图中为什么支持activity、dialog、fragment、navigator四种标签。

public class NavController {
    
    
    public NavController(@NonNull Context context) {
    
    
        mContext = context;
        while (context instanceof ContextWrapper) {
    
    
            if (context instanceof Activity) {
    
    
                mActivity = (Activity) context;
                break;
            }
            context = ((ContextWrapper) context).getBaseContext();
        }
        mNavigatorProvider.addNavigator(new NavGraphNavigator(mNavigatorProvider));
        mNavigatorProvider.addNavigator(new ActivityNavigator(mContext));
    }
}
  1. Fragment回退栈是如何实现的呢?

继续回到NavHostFragment的onCreate方法,找到
mNavController.setOnBackPressedDispatcher(requireActivity().getOnBackPressedDispatcher()); mNavController.setOnBackPressedDispatcher(requireActivity().getOnBackPressedDispatcher());这两句关键代码,其实从字面看它就是控制fragment是否可以实现回退栈的关键。

(1)第一句解析
在这里传入了一句requireActivity().getOnBackPressedDispatcher()
从这里看到传入参数的作用是,获取到Activity的onBackPressed事件

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
    
    
        
	public final OnBackPressedDispatcher getOnBackPressedDispatcher() {
    
    
        return mOnBackPressedDispatcher;
    }
    
    private final OnBackPressedDispatcher mOnBackPressedDispatcher =
            new OnBackPressedDispatcher(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    ComponentActivity.super.onBackPressed();
                }
            });

再回过去看看主体调用方法,

//调用NavHostController
public final void setOnBackPressedDispatcher(@NonNull OnBackPressedDispatcher dispatcher) {
    
    
        super.setOnBackPressedDispatcher(dispatcher);
    }

在这里给onBackPressed事件添加回调

	//NavController
	void setOnBackPressedDispatcher(@NonNull OnBackPressedDispatcher dispatcher) {
    
    
        if (mLifecycleOwner == null) {
    
    
            throw new IllegalStateException("You must call setLifecycleOwner() before calling "
                    + "setOnBackPressedDispatcher()");
        }
        // Remove the callback from any previous dispatcher
        mOnBackPressedCallback.remove();
        // Then add it to the new dispatcher
        dispatcher.addCallback(mLifecycleOwner, mOnBackPressedCallback);
    }

	private final OnBackPressedCallback mOnBackPressedCallback =
            new OnBackPressedCallback(false) {
    
    
        @Override
        public void handleOnBackPressed() {
    
    
            popBackStack();
        }
    };

因此第一句diamante的作用是获取Activity的onBackPressed,以及给back添加回调方法。

(2)第二句解析

//在NavHostController中继续调用NavController的enableOnBackPressed
@Override
    public final void enableOnBackPressed(boolean enabled) {
    
    
        super.enableOnBackPressed(enabled);
    }

将enabled赋值给了mEnableOnBackPressedCallback

void enableOnBackPressed(boolean enabled) {
    
    
        mEnableOnBackPressedCallback = enabled;
        updateOnBackPressedCallbackEnabled();
    }

给回调设置使能开关,其中有两个条件:
第一个条件:mEnableOnBackPressedCallback是判断是否发生了Fragment的切换;
第二个条件:判断Fragment堆栈中的数量是否大于1
第三个隐形条件:app:defaultNavHost="true"时,FragmentManager才能执行commit事物。

//NavController
private void updateOnBackPressedCallbackEnabled() {
    
    
        mOnBackPressedCallback.setEnabled(mEnableOnBackPressedCallback
                && getDestinationCountOnBackStack() > 1);
    }

总结二:Navgator实现回退栈是用过获取到Activity的onBackPress事件,之后给事件注册回调,当满足app:defaultNavHost=“true”,并且Dequa容器中回退Fragment数量大于1时,可以实现Activity回退栈的功能。

3、既然NavControllor是在NavHostFragment的onCreate中创建的,那么navController = Navigation.findNavController(this,R.id.fragment_nav);是做什么?

看到这里知道了其实findNavController其实并未创建NavController,而是通过tag获取的,而tag是在NavHostFragment的onCreateView中赋值的。

public static NavController findNavController(@NonNull Activity activity, @IdRes int viewId) {
    
    
        View view = ActivityCompat.requireViewById(activity, viewId);
        NavController navController = findViewNavController(view);
        if (navController == null) {
    
    
            throw new IllegalStateException("Activity " + activity
                    + " does not have a NavController set on " + viewId);
        }
        return navController;
    }

(4)navController.navigate是如何实现导航功能的?
此处比较简单,就是解析action标签和Destination标签,然后获取指定的页面

public void navigate(@IdRes int resId, @Nullable Bundle args, @Nullable NavOptions navOptions,
            @Nullable Navigator.Extras navigatorExtras) {
    
    
        //当mBackStack是空的时候,获取的是NavHost中的onCreate中setGraph中的值
        NavDestination currentNode = mBackStack.isEmpty()
                ? mGraph
                : mBackStack.getLast().getDestination();
        if (currentNode == null) {
    
    
            throw new IllegalStateException("no current navigation node");
        }
        @IdRes int destId = resId;
        //解析resId获取到action值
        final NavAction navAction = currentNode.getAction(resId);
        Bundle combinedArgs = null;
        if (navAction != null) {
    
    
            if (navOptions == null) {
    
    
                navOptions = navAction.getNavOptions();
            }
            //获取Destination页面
            destId = navAction.getDestinationId();
            Bundle navActionArgs = navAction.getDefaultArguments();
            if (navActionArgs != null) {
    
    
                combinedArgs = new Bundle();
                combinedArgs.putAll(navActionArgs);
            }
        }

        if (args != null) {
    
    
            if (combinedArgs == null) {
    
    
                combinedArgs = new Bundle();
            }
            combinedArgs.putAll(args);
        }

        if (destId == 0 && navOptions != null && navOptions.getPopUpTo() != -1) {
    
    
            popBackStack(navOptions.getPopUpTo(), navOptions.isPopUpToInclusive());
            return;
        }

        if (destId == 0) {
    
    
            throw new IllegalArgumentException("Destination id == 0 can only be used"
                    + " in conjunction with a valid navOptions.popUpTo");
        }

        NavDestination node = findDestination(destId);
        if (node == null) {
    
    
            final String dest = NavDestination.getDisplayName(mContext, destId);
            if (navAction != null) {
    
    
                throw new IllegalArgumentException("Navigation destination " + dest
                        + " referenced from action "
                        + NavDestination.getDisplayName(mContext, resId)
                        + " cannot be found from the current destination " + currentNode);
            } else {
    
    
                throw new IllegalArgumentException("Navigation action/destination " + dest
                        + " cannot be found from the current destination " + currentNode);
            }
        }
        navigate(node, combinedArgs, navOptions, navigatorExtras);
    }

(5)四种Navigator的添加方式有何不同?
先看看基类,Navigator是抽象类,子类需要实现以下方法,主要看看navigator方法。

public abstract class Navigator<D extends NavDestination> {
    
    
  
    @Retention(RUNTIME)
    @Target({
    
    TYPE})
    @SuppressWarnings("UnknownNullness") // TODO https://issuetracker.google.com/issues/112185120
    //注解,标注是什么类型的Navigator,用于NavigatorProvider中HashMap的key
    public @interface Name {
    
    
        String value();
    }

    /**
     * Construct a new NavDestination associated with this Navigator.
     *
     * <p>Any initialization of the destination should be done in the destination's constructor as
     * it is not guaranteed that every destination will be created through this method.</p>
     * @return a new NavDestination
     */
    @NonNull
    public abstract D createDestination();

    /**
     * Navigate to a destination.
     *
     * <p>Requests navigation to a given destination associated with this navigator in
     * the navigation graph. This method generally should not be called directly;
     * {@link NavController} will delegate to it when appropriate.</p>
     *
     * @param destination destination node to navigate to
     * @param args arguments to use for navigation
     * @param navOptions additional options for navigation
     * @param navigatorExtras extras unique to your Navigator.
     * @return The NavDestination that should be added to the back stack or null if
     * no change was made to the back stack (i.e., in cases of single top operations
     * where the destination is already on top of the back stack).
     */
    @Nullable
    public abstract NavDestination navigate(@NonNull D destination, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Extras navigatorExtras);

    /**
     * Attempt to pop this navigator's back stack, performing the appropriate navigation.
     *
     * <p>Implementations should return {@code true} if navigation
     * was successful. Implementations should return {@code false} if navigation could not
     * be performed, for example if the navigator's back stack was empty.</p>
     *
     * @return {@code true} if pop was successful
     */
    public abstract boolean popBackStack();

    /**
     * Called to ask for a {@link Bundle} representing the Navigator's state. This will be
     * restored in {@link #onRestoreState(Bundle)}.
     */
    @Nullable
    public Bundle onSaveState() {
    
    
        return null;
    }

    /**
     * Restore any state previously saved in {@link #onSaveState()}. This will be called before
     * any calls to {@link #navigate(NavDestination, Bundle, NavOptions, Navigator.Extras)} or
     * {@link #popBackStack()}.
     * <p>
     * Calls to {@link #createDestination()} should not be dependent on any state restored here as
     * {@link #createDestination()} can be called before the state is restored.
     *
     * @param savedState The state previously saved
     */
    public void onRestoreState(@NonNull Bundle savedState) {
    
    
    }

    /**
     * Interface indicating that this class should be passed to its respective
     * {@link Navigator} to enable Navigator specific behavior.
     */
    public interface Extras {
    
    
    }
}

a、FragmentNavigator通过FragmentTransaction.replace的方式添加Fragment

public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
    
    
        if (mFragmentManager.isStateSaved()) {
    
    
            Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
                    + " saved its state");
            return null;
        }
        String className = destination.getClassName();
        if (className.charAt(0) == '.') {
    
    
            className = mContext.getPackageName() + className;
        }
        final Fragment frag = instantiateFragment(mContext, mFragmentManager,
                className, args);
        frag.setArguments(args);
        final FragmentTransaction ft = mFragmentManager.beginTransaction();

        int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
        int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
        int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
        int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
        if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
    
    
            enterAnim = enterAnim != -1 ? enterAnim : 0;
            exitAnim = exitAnim != -1 ? exitAnim : 0;
            popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
            popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
            ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
        }

        ft.replace(mContainerId, frag);
        ft.setPrimaryNavigationFragment(frag);

b、DialogFragmentNavigator是通过show的方式添加的

public NavDestination navigate(@NonNull final Destination destination, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
    
    
        if (mFragmentManager.isStateSaved()) {
    
    
            Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
                    + " saved its state");
            return null;
        }
        String className = destination.getClassName();
        if (className.charAt(0) == '.') {
    
    
            className = mContext.getPackageName() + className;
        }
        final Fragment frag = mFragmentManager.getFragmentFactory().instantiate(
                mContext.getClassLoader(), className);
        if (!DialogFragment.class.isAssignableFrom(frag.getClass())) {
    
    
            throw new IllegalArgumentException("Dialog destination " + destination.getClassName()
                    + " is not an instance of DialogFragment");
        }
        final DialogFragment dialogFragment = (DialogFragment) frag;
        dialogFragment.setArguments(args);
        dialogFragment.getLifecycle().addObserver(mObserver);

        dialogFragment.show(mFragmentManager, DIALOG_TAG + mDialogCount++);

        return destination;
    }

c、ActivityNovigator是通过startActivity的方式添加的

public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
    
    
        if (destination.getIntent() == null) {
    
    
            throw new IllegalStateException("Destination " + destination.getId()
                    + " does not have an Intent set.");
        }
        Intent intent = new Intent(destination.getIntent());
        if (args != null) {
    
    
            intent.putExtras(args);
            String dataPattern = destination.getDataPattern();
            if (!TextUtils.isEmpty(dataPattern)) {
    
    
                // Fill in the data pattern with the args to build a valid URI
                StringBuffer data = new StringBuffer();
                Pattern fillInPattern = Pattern.compile("\\{(.+?)\\}");
                Matcher matcher = fillInPattern.matcher(dataPattern);
                while (matcher.find()) {
    
    
                    String argName = matcher.group(1);
                    if (args.containsKey(argName)) {
    
    
                        matcher.appendReplacement(data, "");
                        //noinspection ConstantConditions
                        data.append(Uri.encode(args.get(argName).toString()));
                    } else {
    
    
                        throw new IllegalArgumentException("Could not find " + argName + " in "
                                + args + " to fill data pattern " + dataPattern);
                    }
                }
                matcher.appendTail(data);
                intent.setData(Uri.parse(data.toString()));
            }
        }
        if (navigatorExtras instanceof Extras) {
    
    
            Extras extras = (Extras) navigatorExtras;
            intent.addFlags(extras.getFlags());
        }
        if (!(mContext instanceof Activity)) {
    
    
            // If we're not launching from an Activity context we have to launch in a new task.
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        if (navOptions != null && navOptions.shouldLaunchSingleTop()) {
    
    
            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        }
        if (mHostActivity != null) {
    
    
            final Intent hostIntent = mHostActivity.getIntent();
            if (hostIntent != null) {
    
    
                final int hostCurrentId = hostIntent.getIntExtra(EXTRA_NAV_CURRENT, 0);
                if (hostCurrentId != 0) {
    
    
                    intent.putExtra(EXTRA_NAV_SOURCE, hostCurrentId);
                }
            }
        }
        final int destId = destination.getId();
        intent.putExtra(EXTRA_NAV_CURRENT, destId);
        if (navOptions != null) {
    
    
            // For use in applyPopAnimationsToPendingTransition()
            intent.putExtra(EXTRA_POP_ENTER_ANIM, navOptions.getPopEnterAnim());
            intent.putExtra(EXTRA_POP_EXIT_ANIM, navOptions.getPopExitAnim());
        }
        if (navigatorExtras instanceof Extras) {
    
    
            Extras extras = (Extras) navigatorExtras;
            ActivityOptionsCompat activityOptions = extras.getActivityOptions();
            if (activityOptions != null) {
    
    
                ActivityCompat.startActivity(mContext, intent, activityOptions.toBundle());
            } else {
    
    
                mContext.startActivity(intent);
            }
        } else {
    
    
            mContext.startActivity(intent);
        }
        if (navOptions != null && mHostActivity != null) {
    
    
            int enterAnim = navOptions.getEnterAnim();
            int exitAnim = navOptions.getExitAnim();
            if (enterAnim != -1 || exitAnim != -1) {
    
    
                enterAnim = enterAnim != -1 ? enterAnim : 0;
                exitAnim = exitAnim != -1 ? exitAnim : 0;
                mHostActivity.overridePendingTransition(enterAnim, exitAnim);
            }
        }

        // You can't pop the back stack from the caller of a new Activity,
        // so we don't add this navigator to the controller's back stack
        return null;
    }

d、NavGraphNavigator是通过navigate方式添加的。

public NavDestination navigate(@NonNull NavGraph destination, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Extras navigatorExtras) {
    
    
        int startId = destination.getStartDestination();
        if (startId == 0) {
    
    
            throw new IllegalStateException("no start destination defined via"
                    + " app:startDestination for "
                    + destination.getDisplayName());
        }
        NavDestination startDestination = destination.findNode(startId, false);
        if (startDestination == null) {
    
    
            final String dest = destination.getStartDestDisplayName();
            throw new IllegalArgumentException("navigation destination " + dest
                    + " is not a direct child of this NavGraph");
        }
        Navigator<NavDestination> navigator = mNavigatorProvider.getNavigator(
                startDestination.getNavigatorName());
        return navigator.navigate(startDestination, startDestination.addInDefaultArgs(args),
                navOptions, navigatorExtras);
    }

猜你喜欢

转载自blog.csdn.net/qq_41672484/article/details/115255557