关于自定义MenuItem导致的IllegalArgumentException

本文介绍了一个在更改Android应用中MenuItem字体颜色时遇到的问题,该操作引发了系统错误,导致应用程序崩溃。通过调整onMenuItemSelected方法的实现,成功解决了这一问题。

问题诱因:

使用如下代码更改MenuItem字体:

SpannableString spannableTitle = new SpannableString(itemTitle);
							
if(i==0){
	spannableTitle.setSpan(new ForegroundColorSpan(Color.RED), 0, spannableTitle.length(), 0);
}else{
								
	spannableTitle.setSpan(new ForegroundColorSpan(Color.BLACK), 0, spannableTitle.length(), 0);
}
secondaryMenu.getSubMenu().add(R.id.item_secondary_menu, i, Menu.NONE, spannableTitle);


导致下面的BUG:

10-21 15:01:40.830: W/System.err(21013): java.lang.IllegalArgumentException: Invalid payload item type

10-21 15:01:40.840: W/System.err(21013): at android.util.EventLog.writeEvent(Native Method)
10-21 15:01:40.840: W/System.err(21013): at android.app.Activity.onMenuItemSelected(Activity.java:2596)
10-21 15:01:40.840: W/System.err(21013): at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:366)
10-21 15:01:40.840: W/System.err(21013): at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1000)
10-21 15:01:40.840: W/System.err(21013): at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
10-21 15:01:40.840: W/System.err(21013): at com.android.internal.view.menu.SubMenuBuilder.dispatchMenuItemSelected(SubMenuBuilder.java:81)
10-21 15:01:40.840: W/System.err(21013): at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:154)
10-21 15:01:40.840: W/System.err(21013): at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
10-21 15:01:40.840: W/System.err(21013): at com.android.internal.view.menu.MenuPopupHelper.onItemClick(MenuPopupHelper.java:188)
10-21 15:01:40.840: W/System.err(21013): at android.widget.AdapterView.performItemClick(AdapterView.java:298)
10-21 15:01:40.840: W/System.err(21013): at android.widget.AbsListView.performItemClick(AbsListView.java:1165)
10-21 15:01:40.840: W/System.err(21013): at android.widget.AbsListView$PerformClick.run(AbsListView.java:3020)
10-21 15:01:40.840: W/System.err(21013): at android.widget.AbsListView$5.run(AbsListView.java:3928)
10-21 15:01:40.840: W/System.err(21013): at android.os.Handler.handleCallback(Handler.java:725)
10-21 15:01:40.840: W/System.err(21013): at android.os.Handler.dispatchMessage(Handler.java:92)
10-21 15:01:40.840: W/System.err(21013): at android.os.Looper.loop(Looper.java:137)
10-21 15:01:40.845: W/System.err(21013): at android.app.ActivityThread.main(ActivityThread.java:5069)
10-21 15:01:40.845: W/System.err(21013): at java.lang.reflect.Method.invokeNative(Native Method)
10-21 15:01:40.845: W/System.err(21013): at java.lang.reflect.Method.invoke(Method.java:511)
10-21 15:01:40.845: W/System.err(21013): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
10-21 15:01:40.845: W/System.err(21013): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)

10-21 15:01:40.845: W/System.err(21013): at dalvik.system.NativeStart.main(Native Method)


解决方案:

不再调用super.onMenuItemSelected(),如下所示:

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {

		return true;
	}


<think>我们正在处理一个Android导航错误。错误信息显示:IgnoringonNavDestinationSelectedforMenuItemcom.example.kucun2:id/nav_diandanasitcannotbefoundfromthecurrentdestinationDestination(com.example.kucun2:id/nav_kucun)具体异常:java.lang.IllegalArgumentException:Navigationaction/destinationcom.example.kucun2:id/nav_diandancannotbefoundfromthecurrentdestinationDestination(com.example.kucun2:id/nav_kucun)这个错误发生在用户试图从当前目的地(InventoryFragment,对应的导航节点是nav_kucun)导航到目标目的地(nav_diandan)时。原因分析:在Navigation组件中,每个目的地(destination)只能导航到在导航图中明确定义为直接可达的目的地。也就是说,从当前的目的地(nav_kucun)必须有一条动作(action)指向目标目的地(nav_diandan),或者目标目的地是全局动作(globalaction)可达的。可能的原因:1.在导航图(nav_graph.xml)中,从当前目的地(nav_kucun)到目标目的地(nav_diandan)没有定义动作(action)。2.可能定义了动作,但是动作的ID并不是`nav_diandan`,而是其他ID。3.当前的目的地(nav_kucun)并不是在导航图中定义的目的地,或者目标目的地(nav_diandan)不存在。解决方案:1.检查导航图,确保从`nav_kucun`到`nav_diandan`定义了一个动作。例如:```xml<fragmentandroid:id="@+id/nav_kucun"...><actionandroid:id="@+id/action_nav_kucun_to_nav_diandan"app:destination="@id/nav_diandan"/></fragment>```2.如果使用菜单项(MenuItem)的导航,确保在菜单项中设置了正确的动作ID(而不是目的地ID)。通常菜单项这样配置:```xml<itemandroid:id="@+id/nav_diandan"android:title="点单"app:showAsAction="ifRoom"app:action="@id/action_nav_kucun_to_nav_diandan"/>```注意:这里`app:action`应该指向动作ID(如`action_nav_kucun_to_nav_diandan`),而不是目的地ID(`nav_diandan`)。3.如果确实需要从任意地方导航到`nav_diandan`,可以定义一个全局动作(globalaction)。在导航图的根元素中添加:```xml<actionandroid:id="@+id/action_global_nav_diandan"app:destination="@id/nav_diandan"/>```然后使用全局动作ID(`action_global_nav_diandan`)来导航。4.在代码中导航时,确保使用的是动作ID(如R.id.action_nav_kucun_to_nav_diandan)而不是目的地ID。代码示例(正确使用动作):假设我们有一个NavController实例,我们可以这样导航:```javaNavControllernavController=Navigation.findNavController(activity,R.id.nav_host_fragment);//使用动作ID导航navController.navigate(R.id.action_nav_kucun_to_nav_diandan);```而不是使用目的地ID(错误示例):```javanavController.navigate(R.id.nav_diandan);//这可能会导致问题,除非有全局动作```5.如果使用菜单,通常在onNavigationItemSelected方法中,建议使用NavigationUI的onNavDestinationSelected方法,它会自动处理动作。确保菜单项中的id与导航图中的动作ID匹配(或者菜单项id与目的地id匹配,但不推荐)。如果错误是在使用菜单时发生的,检查菜单项的id是否与导航图中的目的地id一致?但根据错误信息,你似乎是在菜单项中使用了目的地id,而NavigationUI期望菜单项的id与目的地id匹配。但是,从错误信息看,当前目的地(nav_kucun)没有直接到nav_diandan的动作,所以NavigationUI无法找到相应的动作。因此,有两种做法:做法一:使用菜单项id匹配目的地id,并确保在导航图中从每个可能导航到该目的地的起始点都有动作。但这可能不现实。做法二(推荐):使用全局动作。修改菜单项,使其id不一定要和目的地id相同,而是使用一个自定义id,然后在点击时执行全局动作。例如,在菜单项点击事件中:```java@OverridepublicbooleanonNavigationItemSelected(@NonNullMenuItemitem){intid=item.getItemId();NavControllernavController=Navigation.findNavController(this,R.id.nav_host_fragment);if(id==R.id.menu_item_diandan){//这里菜单项id不再是目的地id//使用全局动作idnavController.navigate(R.id.action_global_nav_diandan);returntrue;}//其他菜单项...returnfalse;}```或者,你可以将全局动作绑定到菜单项,但是菜单项的id仍然需要匹配一个动作?不,菜单项id可以任意,只要在点击时执行正确的动作即可。但是,如果你希望使用NavigationUI.setupWithNavController(navigationView,navController),那么要求菜单项的id必须与导航图中的目的地id一致。如果使用全局动作,这种方法就不行。此时,你可以在导航图中为每个目的地添加一个全局动作,但这样菜单项id还是必须匹配目的地id。所以,一个替代方案是:不使用NavigationUI自动绑定,而是手动处理菜单点击,并执行全局动作。总结步骤:1.在导航图中添加全局动作:```xml<navigationxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/nav_graph"app:startDestination="@id/nav_kucun"><fragmentandroid:id="@+id/nav_kucun"...>...</fragment><fragmentandroid:id="@+id/nav_diandan".../><actionandroid:id="@+id/action_global_nav_diandan"app:destination="@id/nav_diandan"/></navigation>```2.修改菜单项,给这个菜单项一个自定义id(比如`menu_item_diandan`),不要与目的地id相同。3.在Activity中处理菜单点击:```java@OverridepublicbooleanonNavigationItemSelected(@NonNullMenuItemitem){if(item.getItemId()==R.id.menu_item_diandan){//使用全局动作导航navController.navigate(R.id.action_global_nav_diandan);drawerLayout.closeDrawer(GravityCompat.START);returntrue;}//其他菜单项可以继续使用自动绑定(如果需要)或者同样处理returnfalse;}```4.移除原来的NavigationUI自动绑定(因为我们已经手动处理),或者如果你只部分菜单项需要特殊处理,可以保留自动绑定,将需要全局动作的菜单项单独处理。如果你不想改变菜单项id,也可以将菜单项的id设置成全局动作的id(即`action_global_nav_diandan`),这样NavigationUI会自动找到全局动作。但是全局动作的id通常较长,而且一般不建议这样。另一种做法:保持菜单项id为目的地id,然后使用全局动作覆盖。在导航图中,为全局动作设置相同的id(即id设为`nav_diandan`)?这可能会冲突。所以,推荐使用手动导航的方式,这样更灵活。如果问题仍未解决,请检查导航图是否包含了所有目的地和动作,并确保在正确的NavHostFragment中操作。由于没有具体的导航图代码,这里只能提供一般性建议。请根据实际情况调整。</think> ### Android导航组件异常解决方案分析 根据您提供的日志,问题出在Android Navigation组件上:`Navigation action/destination com.example.kucun2:id/nav_diandan cannot be found from the current destination`。这表明在尝试从`InventoryFragment`(导航节点ID为`nav_kucun`)导航到`nav_diandan`时,系统找不到有效的导航路径。 以下是完整的解决方案: ```xml <!-- res/navigation/nav_graph.xml 修正导航图 --> <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/nav_kucun"> <!-- 设置初始目的地 --> <!-- 库存管理Fragment --> <fragment android:id="@+id/nav_kucun" android:name="com.example.kucun2.ui.bancai.InventoryFragment" android:label="Gallery" tools:layout="@layout/fragment_inventory"> <!-- 明确声明到点单页面的导航 --> <action android:id="@+id/action_kucun_to_diandan" app:destination="@id/nav_diandan" /> </fragment> <!-- 点单Fragment --> <fragment android:id="@+id/nav_diandan" android:name="com.example.kucun2.ui.bancai.OrderFragment" android:label="点单管理" tools:layout="@layout/fragment_order" /> </navigation> ``` ```kotlin // InventoryFragment.kt 修复导航代码 class InventoryFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 正确使用navigation-safe args插件传递参数 val toOrder = NavDirections.ActionKucunToDiandan().apply { // 如果需要传递参数 // args = Bundle().apply { putString("key", "value") } } // 找到需要触发导航的UI元素 val orderButton = view.findViewById<Button>(R.id.btn_to_order) orderButton.setOnClickListener { // 安全导航:使用已定义的动作ID Navigation.findNavController(view).navigate(toOrder) } } } ``` ```kotlin // MainActivity.kt 确保正确设置NavController class MainActivity : AppCompatActivity() { private lateinit var navController: NavController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取NavHostFragment的引用 val navHostFragment = supportFragmentManager .findFragmentById(R.id.nav_host_fragment) as NavHostFragment // 设置导航控制器 navController = navHostFragment.navController // 设置NavigationUI(如果使用Drawer或BottomNavigation) NavigationUI.setupActionBarWithNavController(this, navController) } // 处理返回键导航 override fun onSupportNavigateUp(): Boolean { return navController.navigateUp() || super.onSupportNavigateUp() } } ``` ### 错误分析及解决方案 #### 问题原因: 1. **导航路径未定义**:当前Fragment(`InventoryFragment` ID为`nav_kucun`)缺少指向目标Fragment(`nav_diandan`)的导航动作 2. **错误引用目标ID**:代码尝试直接使用目标Fragment的ID进行导航(`R.id.nav_diandan`)而不是使用动作ID 3. **导航范围问题**:目标Fragment可能不在当前导航图范围内 #### 解决方案说明: 1. **在导航图中定义明确路径**: ```xml <action android:id="@+id/action_kucun_to_diandan" app:destination="@id/nav_diandan" /> ``` - 每个源目的地需要明确定义可达的目标目的地 - 每个动作需要唯一ID 2. **使用安全导航API**: ```kotlin // 生成安全导航指令 Navigation.findNavController(view).navigate(toOrder) ``` - 使用生成的`NavDirections`对象而不是原始ID - 避免参数类型错误和导航目标不存在问题 3. **导航UI集成**: ```kotlin NavigationUI.setupActionBarWithNavController(this, navController) ``` - 自动管理ActionBar返回按钮 - 保持导航状态一致性 ### 相关调试技巧 1. 使用**Navigation Editor**可视化检查导航图: ``` View > Tool Windows > Navigation ``` 2. 启用导航日志: ```kotlin navController.addOnDestinationChangedListener { _, destination, _ -> Log.d("NAV", "Navigated to: ${destination.label}") } ``` 3. 验证NavHostFragment是否正确声明: ```xml <!-- activity_main.xml --> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph" /> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值