异常日志:

java.lang.IllegalArgumentException: Navigation action/destination com.xxx.xxx:id/action_AFragnebt_to_BFragment cannot be found from the current destination Destination(com.xxx.xxx:id/BFragment) label=BFragment class=com.XXX.XXX.ui.fragment.setting.BFragmentat androidx.navigation.NavController.navigate(NavController.java:938)at androidx.navigation.NavController.navigate(NavController.java:875)at androidx.navigation.NavController.navigate(NavController.java:861)at androidx.navigation.NavController.navigate(NavController.java:849)at com.XXX.XXX.ui.fragment.delivery.AFragment.onClickListener(AFragment.kt:290)at android.view.View.performClick(View.java:7259)at android.view.View.performClickInternal(View.java:7236)at android.view.View.access$3600(View.java:801)at android.view.View$PerformClick.run(View.java:27896)at android.os.Handler.handleCallback(Handler.java:883)at android.os.Handler.dispatchMessage(Handler.java:100)at android.os.Looper.loop(Looper.java:214)at android.app.ActivityThread.main(ActivityThread.java:7397)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

异常日志对应代码:

com.xxx.xxx:id/action_AFragnebt_to_BFragment cannot be found from the current destination Destination(com.xxx.xxx:id/BFragment)
从代码看跳转的时候是在BFragment中调用的NavHostFragment.findNavController(this).navigate(R.id.action_AFragnebt_to_BFragment)进行的页面跳转,而从异常日志却提示的是BFragment中没查找到这个action,为何是从BFragment查找而不是实际跳转位置的AFragment ?

开始分析源码:
先分析NavHostFragment.findNavController(this)是如何获取到的NavController对象

NavHostFragment.java@NonNull
public static NavController findNavController(@NonNull Fragment fragment) {Fragment findFragment = fragment;//如果当前fragment或者其parentFragment有继承了NavHostFragment的话就直接获取对应的NavControllerwhile (findFragment != null) { if (findFragment instanceof NavHostFragment) {return ((NavHostFragment) findFragment).getNavController();}Fragment primaryNavFragment = findFragment.getParentFragmentManager().getPrimaryNavigationFragment();if (primaryNavFragment instanceof NavHostFragment) {return ((NavHostFragment) primaryNavFragment).getNavController();}findFragment = findFragment.getParentFragment();}// Try looking for one associated with the view instead, if applicable//我们的AFragment和BFragment都没有继承NavHostFragment,实际走下面逻辑View view = fragment.getView();if (view != null) {return Navigation.findNavController(view);}// For DialogFragments, look at the dialog's decor viewDialog dialog = fragment instanceof DialogFragment? ((DialogFragment) fragment).getDialog(): null;if (dialog != null && dialog.getWindow() != null) {return Navigation.findNavController(dialog.getWindow().getDecorView());}throw new IllegalStateException("Fragment " + fragment+ " does not have a NavController set");}

从上面NavHostFragment源码可以分析出最终走了Navigation.findNavController(view)获取NavController。

Navigation.java@NonNull
public static NavController findNavController(@NonNull View view) {NavController navController = findViewNavController(view);if (navController == null) {throw new IllegalStateException("View " + view + " does not have a NavController set");}return navController;
}@Nullable
private static NavController findViewNavController(@NonNull View view) {//从view以及view的parentView中获取while (view != null) {NavController controller = getViewNavController(view);if (controller != null) {return controller;}ViewParent parent = view.getParent();view = parent instanceof View ? (View) parent : null;}return null;
}@Nullable
private static NavController getViewNavController(@NonNull View view) {//从view的tag中获取Object tag = view.getTag(R.id.nav_controller_view_tag);NavController controller = null;if (tag instanceof WeakReference) {controller = ((WeakReference<NavController>) tag).get();} else if (tag instanceof NavController) {controller = (NavController) tag;}return controller;
}

从上面源码可以看出,最终是通过fragment中的view,或者parentView的一个R.id.nav_controller_view_tag的tag中拿到的NavController,而在NavHostFragment的onCreate中new了一个NavHostController,并在onViewCreate中为其布局view添加了tagR.id.nav_controller_view_tag传入了这个NavHostController对象

NavHostFragment.java@CallSuper
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {final Context context = requireContext();mNavController = new NavHostController(context);.....................super.onCreate(savedInstanceState);
}@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);if (!(view instanceof ViewGroup)) {throw new IllegalStateException("created host view " + view + " is not a ViewGroup");}Navigation.setViewNavController(view, mNavController);// When added programmatically, we need to set the NavController on the parent - i.e.,// the View that has the ID matching this NavHostFragment.if (view.getParent() != null) {mViewParent = (View) view.getParent();if (mViewParent.getId() == getId()) {Navigation.setViewNavController(mViewParent, mNavController);}}
}//Navigation中的setViewNavController()
public static void setViewNavController(@NonNull View view,@Nullable NavController controller) {//通过R.id.nav_controller_view_tag传入了controllerview.setTag(R.id.nav_controller_view_tag, controller);
}

而AFragment和BFragment对应的同一个activity布局如下,最终获取到的是设置的同一个NavHostFragment中的NavController。

<androidx.constraintlayout.widget.ConstraintLayout 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"><androidx.fragment.app.FragmentContainerViewandroid:id="@+id/fmContainer"android:name="androidx.navigation.fragment.NavHostFragment"android:layout_width="match_parent"android:layout_height="match_parent"app:defaultNavHost="true"app:navGraph="@navigation/navigation_XX_task"/></androidx.constraintlayout.widget.ConstraintLayout>

接下来分析的navigate跳转:
如果在AFragment连续调用两次navigate(R.id.action_AFragment_to_BFragment),当第一次的跳转数据加入到mBackStack后,再次调用一次navigate(R.id.action_AFragment_to_BFragment)。

public void navigate(@IdRes int resId, @Nullable Bundle args, @Nullable NavOptions navOptions,@Nullable Navigator.Extras navigatorExtras) {//如果mBackStack栈不是空就获取最后的加入的NavDestination,//当第一次跳转后mBackStack.getLast().getDestination()对应的是BFragment的NavDestination NavDestination currentNode = mBackStack.isEmpty()? mGraph: mBackStack.getLast().getDestination();if (currentNode == null) {throw new IllegalStateException("no current navigation node");}//destId=R.id.action_AFragment_to_BFragment@IdRes int destId = resId;//在BFragment的NavDestination中没有R.id.action_AFragment_to_BFragment//此时navAction==nullfinal NavAction navAction = currentNode.getAction(resId);Bundle combinedArgs = null;if (navAction != null) {if (navOptions == null) {navOptions = navAction.getNavOptions();}destId = navAction.getDestinationId();Bundle navActionArgs = navAction.getDefaultArguments();if (navActionArgs != null) {combinedArgs = new Bundle();combinedArgs.putAll(navActionArgs);}}
..................................//此处返回的node==nullNavDestination 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 {//navAction为null 走这边throw new IllegalArgumentException("Navigation action/destination " + dest+ " cannot be found from the current destination " + currentNode);}}navigate(node, combinedArgs, navOptions, navigatorExtras);}@SuppressWarnings("WeakerAccess") /* synthetic access */NavDestination findDestination(@IdRes int destinationId) {//destinationId==R.id.action_AFragment_to_BFragmentif (mGraph == null) {return null;}if (mGraph.getId() == destinationId) {return mGraph;}//第二次跳转时 currentNode 对应的是BFragment的NavDestinationNavDestination currentNode = mBackStack.isEmpty()? mGraph: mBackStack.getLast().getDestination();NavGraph currentGraph = currentNode instanceof NavGraph? (NavGraph) currentNode: currentNode.getParent();//从BFragment的Graph中没有 R.id.action_AFragment_to_BFragment//返回nullreturn currentGraph.findNode(destinationId);}

结论:通过代码分析如果在AFragment执行一次到BFragment的跳转后,一定的情况下(已经跳到BFragment并将BFragment加入到BackStack队列中后) 再次执行从A到B的跳转就会出现上述异常崩溃。

简单粗暴的解决方案

//将navigate这一步加上try catch,防止出现上述崩溃
fun NavController.navigateSafe(resId: Int, args: Bundle?=null,navOptions : NavOptions?=null) {try {navigate(resId, args,navOptions)} catch (e: Exception) {Pdlog.d("NavigationExt","navigate: resId = $resId args = $args")Pdlog.d("NavigationExt","navigate: "+e)}
}

其他解决思路:

//调用navigate跳转之前先判断
if (navController.currentDestination?.id == R.id.Afragment) {navController.navigate(R.id.action_Afragment_to_Bfragment)
}

Navigation action/destination com.xxx:id/action_x cannot be found from the current destination相关推荐

  1. Certificate for doesn't match any of the subject alternative names: [.xxx.id, .yyy.id, mmm.id]

    强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 最近在调用第三方测试环境的时候日志中报Certificate for doesn't ...

  2. git clone 问题 destination path ‘xxx’ already exists and is not an empty directory.

    git clone 问题 问题 解决 问题 destination path 'xxx' already exists and is not an empty directory. 该目录中已经存在与 ...

  3. Django-(1054, “Unknown column ‘xxx.id‘ in ‘field list‘“)...

    在测试Django引用models中的表时报错: 检查数据库中的表并无id字段,有些表的主键并不是 id 这个字段,django 是默认为模型添加 id 这个字段,并且设置为主键和让其自增.因此在mo ...

  4. java源码解析之反射(二)

    依赖的结构图: 查看全文 http://www.taodudu.cc/news/show-2970933.html 相关文章: js基础 宿主环境 [笔记]实战mpvue2.0多端小程序框架--原生小 ...

  5. Jetpack学习-5-Navigation简单使用

    Androidx中的fragment是v4包中fragment的升级版本,在之前开发中所有用到的v4-fragment相关方法在androidx-fragment都是类似使用的,无非就是v4-Frag ...

  6. Android 官方架构组件 Navigation 使用详解

    前言 前段时间,我在做项目开发的时候对Fragment的管理遇到几个小问题,总觉得在现阶段封装好的Fragment管理器不太优雅.这成为我下决心学习Jetpack在很早之前推出的Navigation库 ...

  7. Navigation 的应用实践

    1.基本使用 第一步,添加依赖 Navigation的依赖添加: dependencies {def nav_version = "2.5.1"// Java language i ...

  8. ios navigation的返回按钮长按_Android Jetpack架构组件 — Navigation入坑详解 [转]

    前言 这是最近看见的觉得比较有意思的文,希望对大家的学习有帮助. Navigation 直接翻译即为导航,它是 Android Jetpack 组件之一,让单 Activity 应用成为首选架构.应用 ...

  9. 有关Android导览(Android Navigation component)

    文章目录 小结 有关Android导览(Android Navigation component) 碰到的问题 参考 小结 在使用Android导览(Android Navigation compon ...

最新文章

  1. 鸿蒙系统首批更新机器,鸿蒙系统升级名单
  2. Numpy中array和matrix转换
  3. JVM调优技巧与经验
  4. 基于Boost::beast模块的协程HTTP服务器
  5. 魔法值是什么?(为什么在阿里巴巴开发手册中提到不允许任何魔法值直接出现在代码中)
  6. sql时间格式转换yyyymm_XML和实体类之间的转换
  7. 响应式API的设计、实现和应用
  8. PyQt5的QAction多次响应triggered信号的处理方式
  9. 测试工程师因迟到和人事大吵一架,结果人事被开除
  10. 编程语言python怎么读-编程零基础应当如何开始学习 Python?
  11. 高一数学计算机教材,高一数学的教学计划
  12. 黑群晖6.1.4-DS3615xs_65217安装使用教程、含下载资源、亲测有效
  13. [Daozy][区块链 EOS 课程]第2课 EOS编译和启动
  14. win10 python安装以及编辑器pycharm安装
  15. 计算机小高考VB程序的选择题,2011江苏小高考物理试卷
  16. 护眼的VS2019黑色主题!把 Visual Studio 2019 主题设置为 JetBrains Darcula 主题,类似 Pycharm, CLion, IntelliJ IDEA
  17. git拉取报错:You have not concluded your merge. (MERGE_HEAD exists)
  18. 串口服务器采集需要通讯协议么,C2000-A2-SDX6000-CX1
  19. 【新塘N76E003】NU-LINK脱机烧写
  20. Jsoup——抖音视频抓取(二)

热门文章

  1. 【IntelliJ IDEA】如何汉化成简体中文
  2. 【C语言】将文本中汉字读入字符数组输出乱码
  3. c语言实现1024点fft程序,数字信号处理的步骤与注意事项,并编写1024个采样点的FFT C语言程序...
  4. 计算机网络管理员绩效考核,网络工程师专业考核方案
  5. emg采集精度_EMG
  6. python猜单词游戏心得_【Python】猜单词游戏
  7. linux查看系统版本
  8. 计算机科学概论读后感
  9. 有关计算机的英语文献及其翻译,计算机专业外文文献论文翻译1
  10. ps怎么清屏_刷屏了的黑洞照片,居然是3分钟PS出来的!