34

I am seeing the following error in my Android crash reports:

android.os.BadParcelableException: ClassNotFoundException when unmarshalling: android.support.v4.view.ViewPager$SavedState
at android.os.Parcel.readParcelable(Parcel.java:1971)
at android.os.Parcel.readValue(Parcel.java:1859)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:2128)
at android.os.Parcel.readSparseArray(Parcel.java:1581)
at android.os.Parcel.readValue(Parcel.java:1916)
at android.os.Parcel.readMapInternal(Parcel.java:2099)
at android.os.Bundle.unparcel(Bundle.java:223)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1225)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:806)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1083)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:635)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1431)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:431)
at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:160)
at android.support.v4.view.ViewPager.populate(ViewPager.java:895)
at android.support.v4.view.ViewPager.populate(ViewPager.java:772)
at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1539)
at android.support.v4.view.ViewPager.computeScroll(ViewPager.java:1422)
at android.view.ViewGroup.drawChild(ViewGroup.java:3028)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2788)
at android.view.ViewGroup.drawChild(ViewGroup.java:3184)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2788)
at android.view.ViewGroup.drawChild(ViewGroup.java:3184)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2788)
at android.view.ViewGroup.drawChild(ViewGroup.java:3184)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2788)
at android.view.View.draw(View.java:11017)
at android.widget.FrameLayout.draw(FrameLayout.java:450)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2175)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2234)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1810)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2695)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

It appears to happen intermittently when resuming an activity. I do not directly access the SavedState class in any code.

user1509445
  • 351
  • 1
  • 3
  • 5
  • I'm experiencing a similar issue, indeed, I dare to say it's identical. It started happening when I switched my `FragmentPagerAdapter` to `FragmentStatePagerAdapter. Did yuo find out why that was happening? P.D: You should try to include some code of yours in your stack overflow questions. – mdelolmo Sep 13 '12 at 14:47
  • 1
    There is a bug on code.google.com related to this: http://code.google.com/p/android/issues/detail?id=37484 – JWGS Oct 01 '12 at 12:42
  • @user379806, in that bug report, there is a workaround that actually solves the issue. It certainly seems to be an Android bug. – mdelolmo Oct 17 '12 at 22:14

5 Answers5

26

I had the same error and here is what I did.

My issue came from using the ViewPager with a FragmentStatePagerAdapter. Inside one of the Fragments from the ViewPager had another ViewPager. Having that second view pager caused this rare bug. Even with or without an adapter on it.

The solution was to simply set setSaveEnabled(false); on the second ViewPager.

Jona
  • 13,325
  • 15
  • 86
  • 129
  • 3
    +1 This was exactly happening to me a ViewPager inside another ViewPager giving the error, thanks for your simple solution! Incredible Android up to today didn't solve this bug. – pvalle Jul 02 '14 at 06:38
14

Following solution worked for me:

package android.support.v4.app;

import android.os.Bundle;
import android.view.ViewGroup;

public abstract class FixedFragmentStatePagerAdapter extends FragmentStatePagerAdapter {

  public FixedFragmentStatePagerAdapter(FragmentManager fm) {
    super(fm);
  }

  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    Fragment f = (Fragment)super.instantiateItem(container, position);
    Bundle savedFragmentState = f.mSavedFragmentState;
    if (savedFragmentState != null) {
      savedFragmentState.setClassLoader(f.getClass().getClassLoader());
    }
    return f;
  }

}

from http://code.google.com/p/android/issues/detail?id=37484#c1

blahdiblah
  • 33,069
  • 21
  • 98
  • 152
Ramanathan
  • 166
  • 1
  • 4
  • Can you please add a summary to this answer? That would make this answer still useful even if the link ever changes or the content is deleted or edited or whatever. – R. Martinho Fernandes Dec 20 '12 at 16:59
  • What is mSavedFragmentState? It could not be found in the Fragment object in my project. – tasomaniac Sep 25 '13 at 09:11
  • 1
    It's a protected field. You have to put your adapter in the package android.support.v4.app to access it... – Kuno Sep 28 '13 at 20:39
8

If you don't want to include the source in v4 package you can declare the "fix" directly in your Adapter

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        final Object fragment = super.instantiateItem(container, position);
        try {
            final Field saveFragmentStateField = Fragment.class.getDeclaredField("mSavedFragmentState");
            saveFragmentStateField.setAccessible(true);
            final Bundle savedFragmentState = (Bundle) saveFragmentStateField.get(fragment);
            if (savedFragmentState != null) {
                savedFragmentState.setClassLoader(Fragment.class.getClassLoader());
            }
        } catch (Exception e) {
            Log.w("CustomFragmentStatePagerAdapter", "Could not get mSavedFragmentState field", e);
        }
        return fragment;
    }
Yaroslav Mytkalyk
  • 16,950
  • 10
  • 72
  • 99
  • 1
    +1, though you'd better not concatenate exception to log message (as it's not likely internally called `e.toString()` will return something useful), but pass it separately: `Log.w("Custom...", "Could not...", e)`. – Nikita Bosik Feb 11 '18 at 00:05
8

In your Activity/Fragment, do the following:

public void onSaveInstanceState(Bundle outState){
     //This MUST be done before saving any of your own or your base class's     variables
    final Bundle mapViewSaveState = new Bundle(outState);
    mapView.onSaveInstanceState(mapViewSaveState);
    outState.putBundle("mapViewSaveState", mapViewSaveState);
   //Add any other variables here.
   super.onSaveInstanceState(outState);
}

public void onCreate(Bundle savedInstanceState){
   super.onCreate(savedInstanceState);
   final Bundle mapViewSavedInstanceState = savedInstanceState != null ?      savedInstance.getBundle("mapViewSaveState") : null;
 mapView.onCreate(mapViewSavedInstanceState);
 //....
}

source: https://code.google.com/p/gmaps-api-issues/issues/detail?id=6237

or another solution is:

map.onCreate(savedInstanceState);

to this:

map.onCreate(null);

Mubarak
  • 1,419
  • 15
  • 22
1

Answer may be late.I used FragmentPagerAdapter instead of using FragmentStatePagerAdapter.Worked for me like a charm!

williamj949
  • 11,166
  • 8
  • 37
  • 51
  • 2
    This does not work consistently in all Android OS. It crashes in some OS. You'll see this when you start testing in multiple devices and OS versions. – S bruce Jul 21 '16 at 05:37