getSerializableExtra and getParcelableExtra are deprecated. What is the alternative?

45.4k views Asked by At

I have upgraded targetSdkVersion and compileSdkVersion to 33.

I am now getting warnings telling me that the getSerializableExtra(name:) and getParcelableExtra(name:) methods are deprecated.

I checked and confirmed from the documentation in the Intent class that these two methods are indeed deprecated.

The documentation suggests that I use the new getSerializableExtra(name:clazz:) and getParcelableExtra(name:clazz:) methods instead.

Can anyone can help me use the new methods?

Example warnings

  1. Warning while getting an Object:

getSerializableExtra_Deprecated_Image

  1. Warning while getting a List or ArrayList:

getSerializableExtra_Deprecated_List_Image

10

There are 10 answers

7
Niklas On BEST ANSWER

This is what I use:

inline fun <reified T : Serializable> Bundle.serializable(key: String): T? = when {
  Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializable(key, T::class.java)
  else -> @Suppress("DEPRECATION") getSerializable(key) as? T
}

inline fun <reified T : Serializable> Intent.serializable(key: String): T? = when {
  Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializableExtra(key, T::class.java)
  else -> @Suppress("DEPRECATION") getSerializableExtra(key) as? T
}

I've also written the same for getParcelable here and requested this to be added to the Support libraries directly

0
Doron Yakovlev Golani On

For those of us who still use Java, this function does the trick:

@SuppressWarnings({"unchecked", "deprecation"})
@Nullable
public static <T extends Serializable> T getSerializable(@Nullable Bundle bundle, @Nullable String key, @NonNull Class<T> clazz) {
    if (bundle != null) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            return bundle.getSerializable(key, clazz);
        } else {
            try {
                return (T) bundle.getSerializable(key);
            } catch (Throwable ignored) {
            }
        }
    }
    return null;
}
0
Reza Zavareh On

You can use top functions to serialize arguments

but I had a problem serializing the List of object

You can use this way to put and get serialized argument data

Because List is not a Serializable Class, you need to convert it to Array List that supports serializable

These functions are used for serializable

 inline fun <reified T : Serializable> Bundle.serializable(key: String): T? = 
     when {
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> 
            getSerializable(key, T::class.java)
        else -> @Suppress("DEPRECATION") getSerializable(key) as? T
     }

inline fun <reified T : Serializable> Intent.serializable(key: String): T? = 
    when {
       Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> 
           getSerializableExtra(key, T::class.java)
       else -> @Suppress("DEPRECATION") getSerializableExtra(key) as? T
    }

and this way handle puts serialized List of objects

  class YourFragment: Fragment {

      private latinit var list: List<YourObject>


      fun newInstance(
           listOfYourObject: List<YourObject>
       ): YourFragment {

           val args = Bundle()
           val yourList= ArrayList<YourObject>()
           yourList.addAll(listOfYourObject)
           args.putSerializable(LIST_KEY, yourList)
        
           val fragment = YourFragment()
           fragment.arguments = args
           return fragment
       }

   }

and now can get serialize of your list object in this way

   override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    requireArguments().serializable<ArrayList<YourObject>>(LIST_KEY)?.let{
        list = it.toList()
    }
   
 }

   
1
Hrk On

Inspired by Mohamad's answer, you can do an extension

fun <T : Serializable?> Bundle.getSerializableCompat(key: String, clazz: Class<T>): T {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) getSerializable(key, clazz)!! else (getSerializable(key) as T)
}

and call it everywhere like this:

   arguments?.getSerializableCompat("my_key", MyClass::class.java)
4
SpiritCrusher On

Haven't used it myself till yet . As the doc says the updated method is

T getSerializableExtra(String, Class<T>) So you can use it as follows i think.

val myPOJOClass = intent.getSerializableExtra("my_intent_key", MyPOJOClass::class.java)
7
Mohamad Seyedi On

method T getSerializableExtra(String, Class<T>) is introduced from android 33. so you shoud use an if block for devices using android below 33.

fun <T : Serializable?> getSerializable(activity: Activity, name: String, clazz: Class<T>): T
{
    return if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
               activity.intent.getSerializableExtra(name, clazz)!!
           else
               activity.intent.getSerializableExtra(name) as T
}

and then you can use it in your activity like this:

val myPOJOClass = getSerializable(this, "my_intent_key", MyPOJOClass::class.java)
0
Man On

Since we already have good answers with Serializable, will answer in favour of Parcelable

If you feel BundleComapt and IntentCompat versions are longer you can create extensions like this and use

inline fun <reified T: Parcelable> Bundle.getParcel(key: String): T? =
    BundleCompat.getParcelable(this, key, T::class.java)

inline fun <reified T: Parcelable> Intent.getParcel(key: String): T? =
    IntentCompat.getParcelableExtra(this, key, T::class.java)
0
Carsten Hagemann On

Expanding upon Rumit Patel's answer, using an inline function with reified type parameter, usage is even simpler. Note that I made the return type nullable, because !! should in my opinion only be used as a last resort (or at caller side).

@Suppress("DEPRECATION")
inline fun <reified T : Serializable> Intent.getSerializable(key: String): T? {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
        this.getSerializableExtra(key, T::class.java)
    else
        this.getSerializableExtra(key) as? T
}

@Suppress("DEPRECATION")
inline fun <reified T : Parcelable> Intent.getParcelable(key: String): T? {
    Timber.d("intentextras parce")
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        this.getParcelableExtra(key, T::class.java)
    } else {
        this.getParcelableExtra(key)
    }
}

@Suppress("DEPRECATION")
inline fun <reified T : Parcelable> Intent.getParcelableArrayList(key: String): ArrayList<T>? {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        this.getParcelableArrayListExtra(key, T::class.java)
    } else {
        this.getParcelableArrayListExtra(key)
    }
}

Usage:

val mode1: Mode = intent.getSerializable("key")
val mode2 = intent.getSerializable<Mode>("key")
0
Rumit Patel On

However, Mohamad Seyedi's answer did the job. But it fails in the case of getting intent data from onActivityResult().

We can't get data using Activity's intent inside onActivityResult(). Below are the solutions I got.

Solution 1: Using extension function:

fun <T : Serializable?> Intent.getSerializable(key: String, m_class: Class<T>): T {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
        this.getSerializableExtra(key, m_class)!!
    else
        this.getSerializableExtra(key) as T
}

Usage:

val myPOJOClass = intent.getSerializable("my_intent_key", MyPOJOClass::class.java)

Solution 2: Using regular function:

fun <T : Serializable?> getSerializable(intent: Intent, key: String, m_class: Class<T>): T {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
        intent.getSerializableExtra(key, m_class)!!
    else
        intent.getSerializableExtra(key) as T
}

Usage:

val myPOJOClass = getSerializable(intent, "my_intent_key", MyPOJOClass::class.java)
0
Hardik Hirpara On
val myPojoClass = getSerializable(intent, "key_name_here", MyPojoTypeClass::class.java)

then, create that function

 private fun <T : Serializable?> getSerializable(intent: Intent, key: String, className: Class<T>): T {
        return if (Build.VERSION.SDK_INT >= 33)
            intent.getSerializableExtra(key, className)!!
        else
            intent.getSerializableExtra(key) as T
    }