一、简述
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。
- 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));
}
}
- 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);
}