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
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.