【问题标题】:Bad magic number for Bundle in AndroidAndroid中Bundle的坏幻数
【发布时间】:2014-11-29 21:09:28
【问题描述】:

我正在使用此代码将数据从一个活动传递到另一个活动:

 @Override
    public void execute(List<Report> reports, Questions question) {
        Intent replyIntent = new Intent(listener, ReplyActivity.class);
        replyIntent.putExtra("id", 0L);
        replyIntent.putExtra("questions", question);
        listener.openReportOk(question);
        listener.startActivity(replyIntent);
    }

Listener 是回调的 Activity 引用。

问题是这个类:

@Table(name = "Questions")
public class Questions extends Entity implements Parcelable {

    public static final Creator<Questions> CREATOR = new Creator<Questions>() {
        public Questions createFromParcel(Parcel source) {
            return new Questions(source);
        }

        public Questions[] newArray(int size) {
            return new Questions[size];
        }
    };

    @TableField(name = "idReport", datatype = DATATYPE_INTEGER)
    private int idReport;
    @TableField(name = "nameReport", datatype = DATATYPE_STRING)
    private String nameReport;
    @TableField(name = "replyGroups", datatype = DATATYPE_STRING)
    private String replyGroups;
    @TableField(name = "questionGroups", datatype = DATATYPE_ENTITY)
    private List<QuestionsGroup> questionsGroup;
    private Boolean canCreateNew;

    public Questions(int idReport, String nameReport, String replyGroups, List<QuestionsGroup> questionsGroup) {
        this.idReport = idReport;
        this.nameReport = nameReport;
        this.replyGroups = replyGroups;
        this.questionsGroup = questionsGroup;
        this.canCreateNew = false;
    }

    public Questions() {
        questionsGroup = new ArrayList<QuestionsGroup>();
    }

    private Questions(Parcel in) {
        this();
        this.idReport = in.readInt();
        this.nameReport = in.readString();
        this.replyGroups = in.readString();
        Bundle b = in.readBundle(QuestionsGroup.class.getClassLoader());
        this.questionsGroup = b.getParcelableArrayList("questionGroups");
        this.canCreateNew = (Boolean) in.readValue(Boolean.class.getClassLoader());
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.idReport);
        dest.writeString(this.nameReport);
        dest.writeString(this.replyGroups);
        Bundle b = new Bundle();
        b.putParcelableArrayList("questionGroups", (ArrayList<QuestionsGroup>) this.questionsGroup);
        dest.writeBundle(b);
        dest.writeValue(this.canCreateNew);
    }
}

当我在 onCreate 方法中收到包裹时:

 private void getData(Intent data) {
        ID = data.getExtras().getLong("id");
        questions = data.getExtras().getParcelable("questions");
    }

我收到此错误:

10-05 13:19:15.508    3499-3499/com.firext.android E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.firext.android, PID: 3499
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.firext.android/com.firext.android.activities.reply.ReplyActivity}: java.lang.IllegalStateException: Bad magic number for Bundle: 0x28
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2255)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2317)
            at android.app.ActivityThread.access$800(ActivityThread.java:143)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1258)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5070)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:631)
     Caused by: java.lang.IllegalStateException: Bad magic number for Bundle: 0x28
            at android.os.BaseBundle.readFromParcelInner(BaseBundle.java:1342)
            at android.os.BaseBundle.<init>(BaseBundle.java:90)
            at android.os.Bundle.<init>(Bundle.java:66)
            at android.os.Parcel.readBundle(Parcel.java:1645)
            at com.firext.android.domain.QuestionsGroup.<init>(QuestionsGroup.java:53)
            at com.firext.android.domain.QuestionsGroup$1.createFromParcel(QuestionsGroup.java:25)
            at com.firext.android.domain.QuestionsGroup$1.createFromParcel(QuestionsGroup.java:23)
            at android.os.Parcel.readParcelable(Parcel.java:2160)
            at android.os.Parcel.readValue(Parcel.java:2066)
            at android.os.Parcel.readListInternal(Parcel.java:2422)
            at android.os.Parcel.readArrayList(Parcel.java:1756)
            at android.os.Parcel.readValue(Parcel.java:2087)
            at android.os.Parcel.readArrayMapInternal(Parcel.java:2393)
            at android.os.BaseBundle.unparcel(BaseBundle.java:221)
            at android.os.Bundle.getParcelableArrayList(Bundle.java:782)
            at com.firext.android.domain.Questions.<init>(Questions.java:58)
            at com.firext.android.domain.Questions.<init>(Questions.java:18)
            at com.firext.android.domain.Questions$1.createFromParcel(Questions.java:22)
            at com.firext.android.domain.Questions$1.createFromParcel(Questions.java:20)
            at android.os.Parcel.readParcelable(Parcel.java:2160)
            at android.os.Parcel.readValue(Parcel.java:2066)
            at android.os.Parcel.readArrayMapInternal(Parcel.java:2393)
            at android.os.BaseBundle.unparcel(BaseBundle.java:221)
            at android.os.Bundle.getParcelable(Bundle.java:738)
            at com.firext.android.activities.reply.ReplyActivity.getData(ReplyActivity.java:72)
            at com.firext.android.activities.reply.ReplyActivity.onCreate(ReplyActivity.java:38)
            at android.app.Activity.performCreate(Activity.java:5720)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1102)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2208)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2317)
            at android.app.ActivityThread.access$800(ActivityThread.java:143)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1258)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5070)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:631)

怎么了?

【问题讨论】:

  • QuestionsGroup 也可以打包吗?
  • 是的,所有属性都是
  • 您可能想检查 QuestionsGroup 实施是否正常,就像在相同的包裹写入和读取顺序中一样。
  • 根据您的堆栈跟踪,它似乎来自 QuestionsGroup
  • 请添加 QuestionsGroup 源代码

标签: java android parcelable


【解决方案1】:

在你正在使用的问题类中

    private List<QuestionsGroup> questionsGroup;

如果它不是 Parcelable,它是否是 Parcelable,要么使它成为 Parcelable,要么在声明 QuestionGroup 列表中添加 transiet,如下所示:- 下面

private transient List<QuestionsGroup> questionsGroup;

【讨论】:

    【解决方案2】:

    这是因为不同的模块编译在不同的 JDK 版本中。 可以通过https://stackoverflow.com/a/30631386/5255006查看JDK版本。 此外,由于读写 Parcel 时的变量类型不同,可能会发生这种情况。

    【讨论】:

    • 你能确定这个吗?我遇到了这个崩溃,我做了和你一样的事情,从 java7 升级到 java8
    【解决方案3】:

    总结

    您在存储和检索QuestionsGroup 的打包信息的方式上似乎存在错误。第 53 行是需要注意的行。

    在写入包裹时,Android 会为每个字段存储一个特殊的“幻数”,以确保您在从包裹中提取字段时使用正确的顺序(请参阅数字定义的详细说明)。

    您收到错误是因为未在预期位置找到幻数 - 这是因为您没有以正确的顺序从包裹中取出字段。


    来自官方源码的详细解释

    [ 下面的解释基于BundleBaseBundle 类的“最新”(在撰写本文时)API21 实现。你可以在这里找到完整的代码:

    您还可以使用 Android SDK Manager 将代码的本地副本安装到您​​的开发机器上,我觉得这非常有用。 ]

    所以...

    写入包裹时,Android 会采取一些安全措施来确保在您尝试拆包时字段对齐。为此,Android 会在字段中附加一个“幻数”,定义为:

    static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
    

    您可以在writeToParcelInner() 的代码中看到这一点(总结如下)

    void writeToParcelInner(Parcel parcel, int flags) {
        if (mParcelledData != null) {
            if (mParcelledData == EMPTY_PARCEL) {
                parcel.writeInt(0);
            } else {
                int length = mParcelledData.dataSize();
                parcel.writeInt(length);
                parcel.writeInt(BUNDLE_MAGIC);
                parcel.appendFrom(mParcelledData, 0, length);
            }
        } else {
    
       .......... extra code chopped out for illustration purposes
    
        }
    }
    

    同样,在从包裹中读取数据时,Android 会在从包裹中返回值之前检查 BUNDLE_MAGIC 号码。

    private void readFromParcelInner(Parcel parcel, int length) {
        if (length == 0) {
            // Empty Bundle or end of data.
            mParcelledData = EMPTY_PARCEL;
            return;
        }
        int magic = parcel.readInt();
        if (magic != BUNDLE_MAGIC) {
            //noinspection ThrowableInstanceNeverThrown
            throw new IllegalStateException("Bad magic number for Bundle: 0x"
                    + Integer.toHexString(magic));
        }
    
       .......... extra code chopped out for illustration purposes
    
    }
    

    在上面的code for API21 BaseBundle 中,您可以根据 logcat 跟踪在第 1342 行看到您的错误。


    解决方法和进一步调试

    原始海报指出QuestionsGroup 可以正确包裹。

    进一步调试此问题的一种方法是远离(当前)新的 API21,它引入了 BaseBundle 类;以 API19 为例,它只使用 Bundle 类。

    如果用户的代码实际上是正确的,那么它更有可能在更成熟的 API 上工作。

    如果代码仍然中断,则很可能是 QuestionsGroup 代码。但是,此外,新的 logcat 跟踪将指向代码的不同部分,可以查看并可能提供对问题的更多洞察。

    除非是 Bundle,第 1730 行,来自方法 readFromParcelInner(),这意味着同样的问题:

        int magic = parcel.readInt();
        if (magic != BUNDLE_MAGIC) {
            //noinspection ThrowableInstanceNeverThrown
            throw new IllegalStateException("Bad magic number for Bundle: 0x"
                    + Integer.toHexString(magic));
        }
    

    相关帖子

    相关信息见以下帖子:

    【讨论】:

      【解决方案4】:

      我不使用 parcel,而是将 id 解析为目标活动,然后从 db 或内存存储中加载实体

      【讨论】:

        【解决方案5】:

        老实说,我从来没有遇到过这样的错误。但我使用不同的方式在我的parcelableQuestions)中存储parcelableQuestionsGroup)的list

           private Questions(Parcel in) {
                this();
                this.idReport = in.readInt();
                this.nameReport = in.readString();
                this.replyGroups = in.readString();
                //Bundle b = in.readBundle(QuestionsGroup.class.getClassLoader());
                //this.questionsGroup = b.getParcelableArrayList("questionGroups");
                this.questionsGroup = in.readTypedList(questionsGroup,QuestionsGroup.CREATOR);
                this.canCreateNew = (Boolean) in.readValue(Boolean.class.getClassLoader());
            }
        

        还有:

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(this.idReport);
            dest.writeString(this.nameReport);
            dest.writeString(this.replyGroups);
            //Bundle b = new Bundle();
            //b.putParcelableArrayList("questionGroups", (ArrayList<QuestionsGroup>) this.questionsGroup);
            //dest.writeBundle(b);
            dest.writeTypedList(questionsGroup);
            dest.writeValue(this.canCreateNew);
        }
        

        我在我的项目中使用了上面的代码并且它工作正常。您可能想尝试一下,因为它既简单又快速。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-01
          • 1970-01-01
          • 2014-02-01
          • 2012-07-12
          • 2010-10-05
          相关资源
          最近更新 更多