Android:java.lang.IllegalArgumentException:无效的负载项类型

29

一些用户向我报告了他们遇到的异常:

java.lang.IllegalArgumentException: Invalid payload item type
at android.util.EventLog.writeEvent(Native Method)
at android.app.Activity.onMenuItemSelected(Activity.java:2452)
at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:846)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:153)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:956)
at com.android.internal.view.menu.IconMenuView.invokeItem(IconMenuView.java:534)
at com.android.internal.view.menu.IconMenuItemView.performClick(IconMenuItemView.java:122)
at android.view.View$PerformClick.run(View.java:11934)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4123)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)

但我不明白哪里出了问题。有人有关于这个问题的想法吗?我试过重复那个异常,但我没有成功。以下是代码

@Override
public boolean onCreateOptionsMenu(Menu menu) {  
   MenuInflater inflater = getMenuInflater();
   inflater.inflate(R.menu.app_menu, menu);
   return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {  
   switch (item.getItemId()) {
   case R.id.about:
      startActivity(new Intent(this, AboutActivity.class));
      return true;
   case R.id.settings:
      startActivity(new Intent(this, SettingsActivity.class));
      return true;
   case R.id.help:
      startActivity(new Intent(this, AboutActivity.class));
      return true;
   }

   return true;
} 

使用 app_menu xlm 文件:

<?xml version="1.0" encoding="utf-8"?>
<menu
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/about"
          android:icon="@android:drawable/ic_menu_info_details"
          android:title="@string/about_menu_item"/>
    <item android:id="@+id/settings"
          android:icon="@android:drawable/ic_menu_preferences"
          android:title="@string/settings_menu_item"/>
</menu>

在onMenuItemSelected()方法中,它是第2452行吗? - D-Dᴙum
23
我只在运行Android 4.1.2的LG设备上观察到了这个崩溃。 - Jason Robinson
只是提供信息:我注意到LG P710、LG E460、LG E610都出现了崩溃的情况。它们都在运行4.1.2版本。很荒谬。 - scana
我在三星GT-S7582上遇到了崩溃问题。Android版本为4.2.2。 - activesince93
在 Samsung GT-P5100 上的 4.2.2 版本也会发生这种情况。 - Romain Scherfflein
11个回答

19

就像其他人所说的那样,当MenuItem标题中有格式时会出现该错误,因为在Activity写入系统EventLog时存在Android错误。

https://android-review.googlesource.com/#/c/47831/

虽然我只看到它在LG上表现出来,但似乎在修复之前的任何Android版本中都会发生。从那次提交中,我能看出最早的发布版本是4.3,但也许我读错了。

在Activity的onMenuItemSelected中,它们使用MenuItem.getTitleCondensed()会导致错误。我没有在任何地方使用压缩标题,据我所知,默认情况下使用它的视图是在v7支持库引入之后,而我们使用的是v4。

因此,我的更改是在基本Activity类中覆盖onMenuItemSelected,并将压缩的标题设置为标题的字符串版本。这使得可以显示格式化的标题(比如自定义字体),然后使用普通字符串版本的标题进行事件日志记录:

@Override
public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
    // fix android formatted title bug
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 
            && item.getTitleCondensed() != null) {
        item.setTitleCondensed(item.getTitleCondensed().toString());
    }

    return super.onMenuItemSelected(featureId, item);
}

也许你只需要在4.1.2版本或只针对LG进行操作,但我不清楚为什么它没有出现在其他版本中。看起来这个错误可能会发生在其他地方。也许有人可以找出是什么时候引入的,但多设置一个字符串似乎并没有太大的风险。


1
感谢这个解决方法。但是请注意,传递到此方法中的ActionMenuItem可能违反getTitleCondensed()的MenuItem合同,即它可能返回null。请参见Android源代码:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.2_r1/com/android/internal/view/menu/ActionMenuItem.java#ActionMenuItem.getTitleCondensed%28%29 - gnuf
是的,@gnuf 说得对。在遇到这个问题后,我已经在我的代码中加入了修复 - 我会更新响应。 - Mike Venzke

12

对于使用 AppCompat 的用户:

您无法覆盖 Activity.onMenuItemSelected()。如果您只需要对 MenuItemtitle 应用格式,而不关心 titleCondensed

    CharSequence rawTitle = "Click here";
    menuItem.setTitleCondensed(rawTitle);

    SpannableString spannableTitle = new SpannableString(rawTitle);
    //...whatever formatting on spannableTitle, you want
    menuItem.setTitle(spannableTitle);

9

这个错误只在我使用自定义字体SpannableString作为ActionBar标题/副标题时发生。移除自定义格式化解决了这个问题。

黑科技(抱歉LG ;-) :

public static void setActionBarTitle(ActionBarActivity a, String s) {
    SpannableString ss = new SpannableString(s);
    ss.setSpan(new TypefaceSpan(a, "Roboto-Light.ttf"), 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    ActionBar actionBar = a.getSupportActionBar();
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setLogo(R.drawable.icon);
    actionBar.setTitle(isManufacturer("LG") ? s : ss);
}

public static boolean isManufacturer(String company) {
    String manufacturer = Build.MANUFACTURER;
    String model = Build.MODEL;

    return (manufacturer.contains(company) || model.contains(company));
}

嗨,Mateusz,我在LG设备上一直遇到同样的错误,并且我们有一个经过设计的操作栏标题。问题是:你是否遇到了相同的错误?因为堆栈跟踪似乎指向菜单而不是操作栏标题。如果您也收到了“onMenuItemSelected”错误,则可能与您所遇到的情况相同。谢谢! - Ferran Maylinch
是的,同样的错误。据我所记,它只发生在安装有4.1版本的LG设备上,并且我也收到了关于菜单而不是ActionBar的报告。查看我的编辑答案以查看防止此错误的hack。 - Mateusz Jablonski
1
谢谢你的想法。请注意,您的黑客将在所有LG设备上激活,包括Nexus 5和其他设备...也许我们还可以添加条件“Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN”,仅在Android 4.1上激活黑客。 - Ferran Maylinch
我在Crashlytics中检查发现,我只在LGE设备(我猜“LGE”是制造商)上的Android 4.1.2版本中出现错误。 - Ferran Maylinch
我知道,我这么做是有目的的;-) 这是对LG的惩罚...(“他们曾经这样做过,他们可以再次这样做”) - Mateusz Jablonski
1
不仅在LG设备上发生,我有一台安装了Android 2.3.6的三星GT-I9000也有同样的问题 :-/ - forlayo

7

我也遇到了同样的问题。结果发现是我试图格式化我的字符串。

    <string name="send">
        <b>Send</b>
    </string>

我改成了:
    <string name="send">
        Send
    </string>

我希望这可以帮到你。
你也可以使用CDATA标签,这里有一个相关的问题链接
        <string name="send">
             <![CDATA[<b>Send</b>]]>
        </string>

感谢Travis指出这一点。


除非用 CDATA 标签保护,否则不能在 strings.xml 文件中使用 HTML。 - Travis

3

我曾经遇到过相同的问题。在研究Android源代码时,我发现这个问题是在写内部日志时出现的,因为它无法打印格式化的文本。

解决方案很简单:通过重新实现这个函数并不调用其超类,跳过这个日志即可。

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    ... // Do your staff
    return true;
}

5
我的活动继承了android.support.v7.app.ActionBarActivity,但是那个方法不能被覆盖,因为它是final的... :( - Ferran Maylinch

2

在onMenuItemSelected(...)中有一个“不太好的”想法。

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
    if (item.getTitle() instanceof SpannableString) {
        SpannableString sp = (SpannableString)item.getTitle();
        Object[] spans = sp.getSpans(0, sp.length(), Object.class);
        if (spans != null && spans.length > 0) {
            // set text without span markups, need for super.onMenuItemSelected(featureId, item);
            item.setTitleCondensed(sp.toString());
            boolean result = super.onMenuItemSelected(featureId, item);
            item.setTitleCondensed(sp);
            return result;
        }
    }


    return super.onMenuItemSelected(featureId, item);
}

这是一种解决方法,例如:

设置原始字符串,克服错误的位置,然后将原始格式化字符串设置回去。在这个例子中,我认为格式化字符串是一个 SpannableString 对象,你可能会使用其他东西。


2

我有同样的问题

Android 4.1 中菜单项的问题在于字符串。

最初,我的菜单项是这样的:

<item android:id="@+id/item1" android:title="@string/ic_login" 
   android:icon="@drawable/ic_login" android:orderInCategory="100" >
</item>

但那并没有起作用。

我将其改为这样:

<item android:id="@+id/item1"
    android:title="Login"
    android:orderInCategory="100"
    android:icon="@drawable/ic_login"
/>

而且那个运行得很好。


我的应用程序有一些活动。它在某些人身上运行良好,但在另一些人身上存在相同的问题。我不知道为什么? - Khai Nguyen

1

对于使用支持库下的DrawerLayout工具栏的任何人,他们也可能会遇到这个问题。通过覆盖默认的导航单击实现,可以解决此问题。

@Override
public void setSupportActionBar(Toolbar toolbar) {
    super.setSupportActionBar(toolbar);
    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            openDrawer();
        }
    });
}

这应该可以运行。

1
我找到了导致这个错误的原因。 在展开菜单中,我设置了标题如下:
menu.setTitle(Html.fromHtml("Menu line #1<br>And what is displayed on line #2"));

当我使用这个设置时,它会导致无效的有效载荷异常。然后我使用

menu.setTitle("Menu line #1. Opps, can not set what is displayed on line #2");

它在我了解的Android上运行良好。 我想让我的菜单有两行,所以使用HTML标签来换行,但只在一个Activity上成功,在另一个上失败了。我不知道发生了什么。有人有另外的想法或解决方案吗?


0

在调用setDisplayHomeAsUp()之后调用setSupportActionBar()似乎也会导致此问题。建议检查多个setSupportActionBar()调用,特别是在基类中是否存在。

删除意外调用setSupportActionBar()后,问题消失了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接