Search code examples
androidparcelableserializable

Parcelable encountered IOException writing serializable object.......................?


I am having a problem when trying to pass an Object reference from an Activity to another and I believe the culprit is the a List that I have as a field on this object. The reason I believe that is because when I change the list to transient, the object seems to be able to pass, but of course that does not solve my problem, since now the list is null in the new Activity.

Code for the Source Activity

    package com.example.animequiz.ui.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import com.example.animequiz.R;
import com.example.animequiz.dao.AnimeDAO;
import com.example.animequiz.model.Anime;
import com.example.animequiz.ui.adapter.AnimeListAdapter;

import java.util.List;

import static com.example.animequiz.ui.activity.HomePageActivityConstants.KEY_ANIME;

public class AnimesActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anime);
        configureAnimeList();
    }

    private void configureAnimeList() {
        ListView animeList = findViewById(R.id.activity_anime_listview);
        final List<Anime> animes = new AnimeDAO().list();
        animeList.setAdapter(new AnimeListAdapter(animes, this));
        animeList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                Anime selectedAnime = animes.get(position);
                goToLevels(selectedAnime);
            }
        });
    }

    private void goToLevels(Anime selectedAnime) {
        Intent intent = new Intent(AnimesActivity.this, LevelsActivity.class);
        intent.putExtra(KEY_ANIME, selectedAnime);
        startActivity(intent);
    }
}

Code for Anime class

    package com.example.animequiz.model;

import java.io.Serializable;
import java.util.List;

public class Anime implements Serializable {

    private final String title;
    private final String image;
    private final List<Level> levelList;

    public Anime(String title, String image, List<Level> levelList) {
        this.title = title;
        this.image = image;
        this.levelList = levelList;
    }

    public String getTitle() {
        return title;
    }

    public String getImage() {
        return image;
    }

    public double getAnimeCompletionPercentage() {
        double animeCompletionPercentage = 0;
        for (Level level: levelList) {
            animeCompletionPercentage += level.getLevelCompletionPercentage();
        }
        animeCompletionPercentage = animeCompletionPercentage/levelList.size();
        return animeCompletionPercentage;
    }

    public List<Level> getLevelList() {
        return levelList;
    }

}

Code for Level

package com.example.animequiz.model;
import java.io.Serializable;
import java.util.List;

public class Level implements Serializable {

    private final List<AnimeCharacter> animeCharacterList;

    public Level(List<AnimeCharacter> animeCharacterList) {
        this.animeCharacterList = animeCharacterList;
    }

    public double getLevelCompletionPercentage() {
        double levelCompletionPercentage = 0;
        for (AnimeCharacter animeCharacter: animeCharacterList) {
            if (animeCharacter.isKnownByPlayer() == true)
                levelCompletionPercentage++;
        }
        levelCompletionPercentage = levelCompletionPercentage/animeCharacterList.size();
        return levelCompletionPercentage;
    }

    public List<AnimeCharacter> getAnimeCharacterList() {
        return animeCharacterList;
    }

}

Logcat

04-09 17:29:28.296 13995-13995/com.example.animequiz E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.animequiz, PID: 13995
    java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.example.animequiz.model.Anime)
        at android.os.Parcel.writeSerializable(Parcel.java:1394)
        at android.os.Parcel.writeValue(Parcel.java:1341)
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:644)
        at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1313)
        at android.os.Bundle.writeToParcel(Bundle.java:1034)
        at android.os.Parcel.writeBundle(Parcel.java:669)
        at android.content.Intent.writeToParcel(Intent.java:7485)
        at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2411)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1496)
        at android.app.Activity.startActivityForResult(Activity.java:3745)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
        at android.app.Activity.startActivityForResult(Activity.java:3706)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
        at android.app.Activity.startActivity(Activity.java:4016)
        at android.app.Activity.startActivity(Activity.java:3984)
        at com.example.animequiz.ui.activity.AnimesActivity.goToLevels(AnimesActivity.java:46)
        at com.example.animequiz.ui.activity.AnimesActivity.access$000(AnimesActivity.java:21)
        at com.example.animequiz.ui.activity.AnimesActivity$1.onItemClick(AnimesActivity.java:38)
        at android.widget.AdapterView.performItemClick(AdapterView.java:305)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1146)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:3053)
        at android.widget.AbsListView.onTouchUp(AbsListView.java:3872)
        at android.widget.AbsListView.onTouchEvent(AbsListView.java:3637)
        at android.view.View.dispatchTouchEvent(View.java:8471)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2399)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2092)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2106)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2106)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2106)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2106)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2106)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2106)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2369)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1719)
        at android.app.Activity.dispatchTouchEvent(Activity.java:2742)
        at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2330)
        at android.view.View.dispatchPointerEvent(View.java:8666)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4123)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3989)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3544)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3597)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3563)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3680)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3571)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3737)
        at android.view

Solution

  • So Java serialization works like a tree. It starts from the root class in your case Anime. Every property of that class should be serializable. It goes recursively in properties. So in your case 'Level' class has property of type 'AnimeCharacter'. It means that 'AnimeCharacter' should also be serializable. And so on. Until you reach the promotive types like string and numbers. Also very important that serializable class should have zero argument constructor. You can ignore this and use 'Gson' also. But understanding this will be useful in future because all serialization engines work in similar fashion.