Подтвердить что ты не робот

Плохой магический номер для Bundle в Android

Я передаю данные из одного действия в другое действие с помощью этого кода:

 @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);
    }

Слушайте его ссылку на активность для обратных вызовов.

Вопросы относятся к этому классу:

@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");
    }

Im получает эту ошибку:

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)

Что не так?

4b9b3361

Ответ 1

Резюме

Похоже, что у вас есть ошибка в том, как вы храните и извлекаете детальную информацию QuestionsGroup. Строка 53 - это линия, на которую следует обратить внимание.

При написании на посылке Android хранит специальное "волшебное число" с каждым полем, чтобы убедиться, что вы используете правильный порядок, вытягивая поля из посылки (см. подробное объяснение определения номера).

Вы получаете ошибку, потому что волшебное число не найдено в ожидаемой позиции - это потому, что вы не берете поля из посылки в правильном порядке.


Подробное объяснение из официального исходного кода

[Ниже объяснение основано на "последней" (на момент написания) реализации API21 классов Bundle и BaseBundle. Здесь вы можете найти полный код:

Вы также можете использовать 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

}

В вышеприведенном коде для API21 BaseBundle вы можете увидеть, что ваша ошибка была выбрана в строке 1342 в соответствии с трассировкой logcat.


Обходной путь и дальнейшая отладка

Оригинальный плакат утверждает, что 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));
    }

Связанные сообщения

См. следующие сообщения для соответствующей информации:

Ответ 2

Честно говоря, я никогда не получал такую ​​ошибку. Но я использую другой способ хранения list parcelable (QuestionsGroup) внутри моего parcelable (Questions):

   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);
}

Я использую выше код в своих проектах и ​​его работоспособность. Возможно, вы захотите попробовать его с самого легкого и быстрого.

Ответ 3

В классе "Вопросы" вы используете

    private List<QuestionsGroup> questionsGroup;

Является Исправляемым или нет, если это не является возможным, либо сделайте его возможным или добавьте трансивер в объявление списка вопросов, например: - ниже

private transient List<QuestionsGroup> questionsGroup;

Ответ 4

Это происходит потому, что разные модули скомпилированы в разных версиях JDK. Вы можете проверить версию JDK на fooobar.com/questions/61094/.... Кроме того, это может произойти из-за разных типов переменных при чтении и записи Parcel.

Ответ 5

вместо того, чтобы использовать посылку, я просто проанализирую идентификатор для целевой активности и загружаю объект обратно из db или в хранилище памяти