Android Parcel の読出しに関連するエラー java.lang.RuntimeException: Parcel android.os.Parcel: Unmarshalling unknown type…

Android Parcel、Parcelableに関連するエラーにかなりはまったので書いておきます。


FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{hogehoge.HogeActivity}: java.lang.RuntimeException: Parcel android.os.Parcel@24940f: Unmarshalling unknown type code 7602259 at offset 2164
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3663)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3820)
	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2218)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:8001)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1039)
Caused by: java.lang.RuntimeException: Parcel android.os.Parcel@24940f: Unmarshalling unknown type code 7602259 at offset 2164
	at android.os.Parcel.readValue(Parcel.java:3306)
	at android.os.Parcel.readArrayMapInternal(Parcel.java:3624)
	at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
	at android.os.BaseBundle.unparcel(BaseBundle.java:236)
	at android.os.BaseBundle.getBoolean(BaseBundle.java:898)

上記のようなエラーが出てしまいます。

細かい説明は割愛しますが、例えばAndroidの画面をまたいで複雑なオブジェクトをやり取りしたい時に、このParcel、Parcelableという仕組みを使います。

Parcelableというインターフェースをimplementsすると、そのクラスがParcelとして扱えるようになります。

例えば次のように作るのですが

public class Hoge implements Parcelable {

    private final int id;
    private final String name;

    public Hoge(int id, String name) {
        this.id = id;
        this.name = name;
    }

    protected Hoge(Parcel in) { 
        id = in.readInt(); // ★この順番と
        name = in.readString();
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(id); // ★ここの順番は一緒でなくてはならない
        dest.writeString(name);
    }

    public static final Creator<Hoge> CREATOR = new Creator<Hoge>() {
        @Override
        public Hoge createFromParcel(Parcel in) {
            if(in.readInt() == 1) {
                return new Hoge2(in);
            }
            return new Hoge(in);
        }

        @Override
        public Hoge[] newArray(int size) {
            return new Hoge[size];
        }
    };

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

}


Parcel inが引数のコンストラクタがParcelを読みだしてコンストラクトします。
writeToParcel()というメソッドで、Parcelに書き出しをします。

あんましここのイメージわきにくかったんですが、BlackHatのYoutubeさんにちょうどよい画像を見つけました。

Android Parcelイメージ
Android Parcelのイメージ

下記からの引用になります。ありがとうございます。
https://www.youtube.com/watch?v=qIzMKfOmIAA&list=LL&index=1

こういう構造だから、読みだしと書き込みが一緒じゃないとダメなんですね。
絵にするとめちゃわかりやすいです!( ˊᵕˋ )

サンプルコードではこの★がついたところが読みだしと書き出しにあたります。

冒頭のエラー はこれが順番通りじゃないと読出しに失敗して起こるエラーだそうです。

何度も目をこすりながら確認しても読出しと書き出しは一緒。
ChatGPTに聞いてもわかりませんでした。

結局、理由はこの部分↓にありました。

    public static final Creator<Hoge> CREATOR = new Creator<Hoge>() {
        @Override
        public Hoge createFromParcel(Parcel in) {
            if(in.readInt() == 1) { // 💀 問題はここだった
                return new Hoge2(in);
            }
            return new Hoge(in);
        }

        @Override
        public Hoge[] newArray(int size) {
            return new Hoge[size];
        }
    };

in.readInt() == 1 で、in の1つ目が使われている、ということみたいです。

この部分をほかに移すことでなんとかなりました。

Creatorの中も注意!ということです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です