Kotlin, how to use getParcelable to keep state across rotation?

308 views Asked by At

I'm trying to use parcelable to maintain state when rotating my device.

val VehiclesParcelable = VehiclesModel()

override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
    super.onSaveInstanceState(outState, outPersistentState)
    outState.putParcelable(KEY, VehiclesParcelable)
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
    if(savedInstanceState != null) {
        savedInstanceState.getParcelable<VehiclesModel>(KEY)
    }
}

I can't figure out how to use the getParcelable, it says it's deprecated, if I try to use the newer version (that says I need to include the class?) getParcelable(KEY, VehiclesModel) I get "type mismatch".

I'm pretty sure I'm putting in the second argument incorrectly.

How do I use the new version? All I find about it just use it like I did in the code above.

1

There are 1 answers

4
Zain On

I can't figure out how to use the getParcelable, it says it's deprecated

As of API level 33, the one-argument getParcelable (String key) is deprecated. Starting from API level 33, you need to include the class as a second argument using the two-argument version getParcelable (String key, Class<T> clazz)

In Kotlin, the KClass formula is used to represent a class, but to get a Java Class instance corresponding to a given KClass instance, extend that with ".java" suffix (documentation reference). This would be in your model "VehiclesModel::class.java".

So, to fix the deprecation after API level 33:

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) // API 33
        @Suppress("DEPRECATION")
        savedInstanceState.getParcelable<VehiclesModel>(KEY)
    else
        savedInstanceState.getParcelable(KEY, VehiclesModel::class.java)
}

Side notes:

  • The condition if(savedInstanceState != null) has been removed because the savedInstanceState argument is not nullable.
  • The VehiclesModel model class is typically a data class, and that expects a constructor with one argument at least, check here. So, you need to fix that in val VehiclesParcelable = VehiclesModel() statement.
  • ViewModel would be a typical tool instead of onSaveInstaceState() if you just want to survive configuration changes.

Update for the bountied part

how would you solve the bountied part? I'm using Java so I'm using if (savedInstanceState != null) instead of a method onRestoreInstanceState.

Even if you're using Java, the the savedInstanceState is annotated with @NonNull; so it shouldn't be null; instead you'd worry if the getParcelable() returned null in case the key was wrong.

The code in java, you'd use Bitmap.class instead of the OP VehiclesModel:

String KEY = "stateOfImageView";

@Override
protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
    Bitmap bitmap = drawable.getBitmap();
    savedInstanceState.putParcelable(KEY, bitmap);
}

@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    Bitmap bitmap;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) // API 33
        bitmap = savedInstanceState.getParcelable(KEY);
    else
        bitmap = savedInstanceState.getParcelable(KEY, Bitmap.class);
    ...
}