Search code examples
javaandroidserializationadmobinterstitial

AdMob Interstitials onSaveInstanceState and Serializables Parcelable encountered IOException writing serializable object


Im saving an array of Serializables in a fragments onSaveInstanceState. This has caused no issues with regular fragment destruction such orientation changes. However when I attempt to display an interstitial ad it causes the application to crash.

07-14 15:30:22.534: E/AndroidRuntime(17681): FATAL EXCEPTION: main
07-14 15:30:22.534: E/AndroidRuntime(17681): Process: com.mydomain.MyApp, PID: 17681
07-14 15:30:22.534: E/AndroidRuntime(17681): java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.mydomain.MyApp.fragments.TimerDisplayFragment$RoundSound)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeSerializable(Parcel.java:1316)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeValue(Parcel.java:1264)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeList(Parcel.java:653)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeValue(Parcel.java:1226)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeArrayMapInternal(Parcel.java:618)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Bundle.writeToParcel(Bundle.java:1692)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeBundle(Parcel.java:636)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.app.FragmentState.writeToParcel(Fragment.java:133)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeTypedArray(Parcel.java:1133)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.app.FragmentManagerState.writeToParcel(FragmentManager.java:373)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeParcelable(Parcel.java:1285)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeValue(Parcel.java:1204)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeArrayMapInternal(Parcel.java:618)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Bundle.writeToParcel(Bundle.java:1692)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeBundle(Parcel.java:636)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:2467)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3084)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Handler.handleCallback(Handler.java:733)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Handler.dispatchMessage(Handler.java:95)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Looper.loop(Looper.java:136)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.app.ActivityThread.main(ActivityThread.java:5001)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.lang.reflect.Method.invokeNative(Native Method)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.lang.reflect.Method.invoke(Method.java:515)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at dalvik.system.NativeStart.main(Native Method)
07-14 15:30:22.534: E/AndroidRuntime(17681): Caused by: java.io.NotSerializableException: com.mydomain.MyApp.fragments.TimerDisplayFragment
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1364)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:979)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:368)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1074)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1404)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
07-14 15:30:22.534: E/AndroidRuntime(17681):    at android.os.Parcel.writeSerializable(Parcel.java:1311)
07-14 15:30:22.534: E/AndroidRuntime(17681):    ... 25 more

The stack trace doesn't point to ant parts in my code aside from the class name I'm attempting to serialize.

While I have had trouble googling this problem I can't be the only one with it since I feel like it would be a rather common use case.

This is the class getting serialized.

    private class RoundSound implements Serializable{

    private static final long serialVersionUID = -6594386620517893228L;
    public String sound;
    public long delay;

    RoundSound(String s, long d){
        sound = s;
        delay = d;
    }       
}

Here is the code that displays the ad.

public static void showInterstitial(Context ctx){
    if(interstitial == null){

        interstitial = new InterstitialAd(ctx);
        interstitial.setAdUnitId(MY_TEST_AD_UNUT);
        AdRequest adRequest = new AdRequest.Builder()
                .addTestDevice("")
                .addTestDevice("")
                .build();
        interstitial.loadAd(adRequest);

    }
    if(actionsToAd <= 0 && !isPro){
        actionsToAd = 3;
        interstitial.show();
        interstitial = null;
    }else{
        actionsToAd--;
    }
}

if anyone could provide some insight or a workaround to this problem it would be much appreciated.


Solution

  • Your RoundSound class seems to be a non-static inner class. Each instance of this class will have a reference to an instance of the outer class (TimerDisplayFragment). So when you serialize a RoundSound instance, it will write the direct properties of the instance and additionally the TimerDisplayFragment instance. However, the fragment instance isn't serializable and that's exactly where the error occurs. Note that the nested exception says that the outer class isn't serializable. It doesn't mention the inner class.

    To fix it, convert the RoundSound class into a static inner class if possible:

    private static class RoundSound implements Serializable {
       ...
    }