1

I see (not regularly - just very rarely = cca 1 in 1000 times) BadParcelableException when trying to retrieve from Bundle.

Anybody has any idea why it happens? I thought it should either happen always, or never, not randomly. This is my code:

  1. Parcelable object I am putting into Bundle:

    public interface ButtonPressedCallback extends Parcelable {
        public void onButtonPressed ();
    }
    
  2. This is how I put it in Bundle

    bundle.putString(MyFragment.TITLE, title);
    bundle.putParcelable(MyFragment.CALLBACK , callback);
    
  3. This is how I retrieve it (and here it crashes)

    public class MyFragment extends Fragment {    
        private String title;
        private ButtonPressedCallback callback;
    
        public static final String TITLE = "TITLE";
        public static final String CALLBACK = "CALLBACK";
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            Bundle b = getArguments();
    
            title = getArguments().getString(TITLE); // it crashes here
            callback = b.getParcelable(CALLBACK );
            ...
       }
    

It mysteriously crashes on line when retrieving just normal string TITLE (weird....) but I am 100% sure that line is ok and it actually crashes below - because it started when I added interface into Bundle

And here is stacktrace:

Caused by: android.os.BadParcelableException: 
  at android.os.Parcel.readParcelableCreator (Parcel.java:2875)
  at android.os.Parcel.readParcelable (Parcel.java:2797)
  at android.os.Parcel.readValue (Parcel.java:2700)
  at android.os.Parcel.readArrayMapInternal (Parcel.java:3067)
  at android.os.BaseBundle.unparcel (BaseBundle.java:257)
  at android.os.BaseBundle.getString (BaseBundle.java:1086)
       at sk.myapp.intro.MyFragment.onCreate (MyFragment.java:42)
  at android.support.v4.app.Fragment.performCreate (Fragment.java:2414)
  at android.support.v4.app.FragmentManagerImpl.moveToState (FragmentManagerImpl.java:1418)
  at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState (FragmentManagerImpl.java:1784)
  at android.support.v4.app.FragmentManagerImpl.moveToState (FragmentManagerImpl.java:1852)
  at android.support.v4.app.FragmentManagerImpl.dispatchStateChange (FragmentManagerImpl.java:3269)
  at android.support.v4.app.FragmentManagerImpl.dispatchCreate (FragmentManagerImpl.java:3223)
  at android.support.v4.app.FragmentController.dispatchCreate (FragmentController.java:190)
  at android.support.v4.app.FragmentActivity.onCreate (FragmentActivity.java:369)
       at sk.myapp.intro.MainActivity.onCreate (MainActivity.java:46)
  at android.app.Activity.performCreate (Activity.java:7183)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1221)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2910)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3032)
  at android.app.ActivityThread.-wrap11 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1696)
  at android.os.Handler.dispatchMessage (Handler.java:105)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6942)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)
qkx
  • 2,383
  • 5
  • 28
  • 50
  • 1
    You should avoid using `Bundle` as there is a limit of 1MB storage & it crashes if it exceeds this limit, instead use `Model` to pass data from one component to other. – Astha Garg Jun 19 '19 at 05:46
  • how can it exceed limit 1 MB when I am just passing some simple callback method? Also, do you have any example of usage? THanks – qkx Jun 19 '19 at 06:01
  • I faced this issue when i was putting a huge Model(sometimes ArrayList of Model) into bundle using `putParcelable` and was using `setArguments(bundle)` while adding a fragment. Let me check the bundle in your scenario. – Astha Garg Jun 19 '19 at 06:06
  • In `bundle.putParcelable(MyFragment.CALLBACK , callback);`, how have u initialized `callback` in your code? what's stored in it? – Astha Garg Jun 19 '19 at 06:19
  • see my anaswer below I posted code (it adds widget on screen) – qkx Jun 19 '19 at 06:31
  • @Astha do you have any tips? (see my answer below) – qkx Jun 20 '19 at 11:26
  • Where is this code `bundle.putString(MyFragment.TITLE, title); bundle.putParcelable(MyFragment.CALLBACK , callback);` written? – Astha Garg Jun 20 '19 at 11:27
  • in one of my classes which is creating fragment – qkx Jun 20 '19 at 11:28
  • Is `callback`(in above question) same as `successCallback` (in below answer)? – Astha Garg Jun 20 '19 at 11:31
  • no thats different thing. My callback is method containing that code below – qkx Jun 20 '19 at 11:34

2 Answers2

1

Writing this since I couldn't provide example in comment ,

@SuppressLint("ParcelCreator")
public class MainActivity extends AppCompatActivity implements CallbackInterface{

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

        Bundle bundle = new Bundle();
        bundle.putParcelable("CALLBACK",this); // <---

    }

    @Override
    public void demoCallback() {

    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {

    }
}

Since I'm passing this, It may crash when my Activity holds lots of member variables (> 1MB)

Astha Garg
  • 1,022
  • 7
  • 21
  • I already solved problem by getting rid of parcelable and just using another callback to my activity. its a bit mroe complicated but I got rid of this exception. Anyway thank you very much for your help and effort, I appreciate it a lot – qkx Jun 20 '19 at 12:37
0

Astha this is in callback (basically just adding widgte on homescreen through button):

AppWidgetManager appWidgetManager =
        context.getSystemService(AppWidgetManager.class);
ComponentName myProvider =
        new ComponentName(context, MyAppWidgetProvider.class);

if (appWidgetManager.isRequestPinAppWidgetSupported()) {
    // Create the PendingIntent object only if your app needs to be notified
    // that the user allowed the widget to be pinned. Note that, if the pinning
    // operation fails, your app isn't notified.
    Intent pinnedWidgetCallbackIntent = new Intent( ... );

    // Configure the intent so that your app's broadcast receiver gets
    // the callback successfully. This callback receives the ID of the
    // newly-pinned widget (EXTRA_APPWIDGET_ID).
    PendingIntent successCallback = PendingIntent.getBroadcast(context, 0,
            pinnedWidgetCallbackIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    appWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
}
qkx
  • 2,383
  • 5
  • 28
  • 50