异常日志:

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)-CDN基本常识 王泽宾
  2. PHP 发邮件《转》
  3. TCP/IP / IP 头
  4. python命令行参数作用_Python命令行参数解析模块argparse
  5. OPPO或将于本月推出Find X2 英雄联盟 S10 限定版
  6. 设计模式系列之「工厂方法模式」
  7. [转载]apache rewrite规则
  8. 生物物种数据库_一个半机械人的物种
  9. A311D项目开发总结
  10. Java基础语法结构
  11. 用指针将字符串逆序输出
  12. T-test检验中的P,α理解
  13. 新西兰 计算机 转专业,新西兰可接受转专业院校
  14. docer启动一个容器时的过程
  15. hdu 3535 AreYouBusy 经典混合背包
  16. java里short,int,long,float,double范围及可写位数
  17. 如何登录无线web认证服务器,路由器如何设置web认证的方式连接免费WIFI
  18. be服务器未正常运行2.6.43,绝地求生be服务器未正常运行 be启动失败怎么办
  19. 谈移动互联网开发的数据分析和决策思路
  20. ​柯洁的2017:20岁,与AI斗与人类斗,其乐无穷 | 焦点

热门文章

  1. 阿里巴巴:今年营收 5000 亿,明年GMV要再增一万亿
  2. Excel自动打开、刷新、保存
  3. Xilinx-7系列FPGA架构—— CLB
  4. Docker常用工具
  5. 微信小程序开发实战11_4 微信支付退款流程
  6. ¥1-2 例2.2 将两个集合的并集放到线性表中
  7. 网吧服务器维护,网吧维护入门教程之无盘原理 | 专业网吧维护
  8. 「ZBrush」学习ZB出来可以从事什么工作?小白都知道吗?
  9. 国标28181:什么是RTSP协议
  10. java连连看解说_java—连连看-实现消除