Rumit Patel
Rumit Patel

Reputation: 12579

getSerializableExtra and getParcelableExtra are deprecated. What is the alternative?

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

Upvotes: 60

Views: 59240

Answers (12)

BenjyTec
BenjyTec

Reputation: 10887

There were compatibility functions added within BundleCompat:

BundleCompat.getSerializable(myBundle, "MySerializableKey", MySerializable::class.java)
BundleCompat.getParcelable(myBundle, "MyParcelableKey", MyParcelable::class.java)

It will behave so that

  • on SDK 34 and above, this method calls the new Bundle.getXYZ(key, T::class.java)
  • on SDK 33 and below, this method calls the old Bundle.getXYZ(key) and performs a checked cast

If the key does not exist or does not match the expected type, null is returned.

Upvotes: 0

Mohammad Tabbara
Mohammad Tabbara

Reputation: 1467

There is a compat funtion for this:

BundleCompat.getSerializable(bundle, name, clazz)

bundle isn't nullable so intent.extras need to be null checked first.

Upvotes: 0

Man
Man

Reputation: 2817

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)

Upvotes: 1

Carsten Hagemann
Carsten Hagemann

Reputation: 1144

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")

Upvotes: 6

Reza Zavareh
Reza Zavareh

Reputation: 325

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()
    }
   
 }

   

Upvotes: 0

Doron Yakovlev Golani
Doron Yakovlev Golani

Reputation: 5480

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;
}

Upvotes: 8

Hardik Hirpara
Hardik Hirpara

Reputation: 3046

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
    }

Upvotes: 1

Niklas
Niklas

Reputation: 25443

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

Upvotes: 75

Rumit Patel
Rumit Patel

Reputation: 12579

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)

Upvotes: 6

Hrk
Hrk

Reputation: 2764

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)

Upvotes: 2

Mohamad Seyedi
Mohamad Seyedi

Reputation: 443

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)

Upvotes: 26

SpiritCrusher
SpiritCrusher

Reputation: 21053

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)

Upvotes: 1

Related Questions