71

I am passing Parcelable data into an Intent and getting it out on the other end using the getParcelableExtra(name:) method. However, getParcelableExtra(name:) seems to be deprecated. How do I fix the deprecation warning? Alternatively, are there any other options for doing this? I am using a compileSdkVersion value of 33.

Code snippet

var data = intent.getParcelableExtra("data")
Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
Rabindra Khadka
  • 1,344
  • 1
  • 13
  • 23

5 Answers5

155

Here are two extension methods that I use for Bundle & Intent:

inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? = when {
  SDK_INT >= 33 -> getParcelableExtra(key, T::class.java)
  else -> @Suppress("DEPRECATION") getParcelableExtra(key) as? T
}

inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? = when {
  SDK_INT >= 33 -> getParcelable(key, T::class.java)
  else -> @Suppress("DEPRECATION") getParcelable(key) as? T
}

I also requested this to be added to the support library

And if you need the ArrayList support there is:

inline fun <reified T : Parcelable> Bundle.parcelableArrayList(key: String): ArrayList<T>? = when {
  SDK_INT >= 33 -> getParcelableArrayList(key, T::class.java)
  else -> @Suppress("DEPRECATION") getParcelableArrayList(key)
}

inline fun <reified T : Parcelable> Intent.parcelableArrayList(key: String): ArrayList<T>? = when {
  SDK_INT >= 33 -> getParcelableArrayListExtra(key, T::class.java)
  else -> @Suppress("DEPRECATION") getParcelableArrayListExtra(key)
}

Note: There are some issues on SDK 33 with the new methods, so you might only want to use it starting from SDK 34.

Niklas
  • 23,674
  • 33
  • 131
  • 170
  • Good solution. Requested here to be part of the android-x: https://issuetracker.google.com/issues/243986223 – android developer Aug 27 '22 at 20:17
  • I've requested this myself. I've updated the description to include the ticket: https://issuetracker.google.com/issues/242048899 – Niklas Aug 28 '22 at 17:48
  • Wait, did I miss it, or you've added it after I wrote it? – android developer Aug 29 '22 at 05:58
  • I've created the feature request myself on August 10th after answering this question here and edited my original answer with my link after you wrote your comment. (So that others can see it directly) – Niklas Aug 29 '22 at 12:08
  • So I didn't miss it. BTW, I think the same exists for getSerializableExtra, too. Maybe for others as well. – android developer Aug 29 '22 at 13:43
  • 1
    Good point. There already exists a question for that so I answered there: https://stackoverflow.com/a/73543350/1979703 – Niklas Aug 30 '22 at 13:33
  • Do you know how to do it for getParcelableArrayListExtra and getParcelableArrayList ? For some reason when I try something similar to what's here, it fails to build... – android developer Sep 05 '22 at 22:26
  • @androiddeveloper updated my answer to include ArrayList support. – Niklas Sep 06 '22 at 17:44
  • It returns List instead of ArrayList. This might be the reason I failed. How come it returns a List? Both functions instead are supposed to return ArrayList. Also, BTW, I think you have the wrong name inside one of them. – android developer Sep 07 '22 at 14:35
  • 1
    @androiddeveloper good call. Now it's updated :) – Niklas Sep 07 '22 at 22:10
  • Seems perfect now! Thank you. How did you know how to change it properly? I always make mistakes with this kind of thing... Also, do you know how such a thing can be called from Java? It seems like it's impossible to reach such functions... – android developer Sep 08 '22 at 09:17
  • @androiddeveloper I've worked a lot with generics in Kotlin, so I know about `reified` and what I can use. It just takes tome. This only works in Kotlin due to `reified` which only works in `inline fun`. There's no such thing in Java. – Niklas Sep 08 '22 at 19:27
  • I didn't mean "how to implement it on Java?". I mean "In some Java classes, how can I reach the functions you've declared here?" – android developer Sep 09 '22 at 10:24
  • You can't. Convert your other classes to use Kotlin :) – Niklas Sep 09 '22 at 11:55
  • So I need to implement something similar, and have duplicates? Too bad. – android developer Sep 09 '22 at 14:40
  • 3
    It seems there is a bug on Android 13 related to this API. Google says they will fix it on the next version and provide something too. So, for now, I think it's better to use `> VERSION_CODES.TIRAMISU` instead of `>= VERSION_CODES.TIRAMISU` . Link: https://issuetracker.google.com/issues/240585930#comment6 – android developer Oct 13 '22 at 06:51
  • Does this code work for getSerializableExtra also ? – K Pradeep Kumar Reddy Jan 09 '23 at 16:32
  • Agreed with @androiddeveloper to use `> VERSION_CODES.TIRAMISU`, I too encountered an NPE when attempting to access the parcelable on Android 13. Looking at the `IntentCompat` implementation for the `core-ktx` library, it looks like they're checking for "at least U", so it's also `> VERSION_CODES.TIRAMISU`. Kinda an egregious miss here to deprecate for Android 13 when they should've been deprecating for 14+. https://android.googlesource.com/platform/frameworks/support/+/b0895cf4dc9a13b63d3d47aeb7b07a99cfc0bd28/core/core/src/main/java/androidx/core/content/IntentCompat.java#211 – Chee-Yi May 30 '23 at 10:39
  • good solution, thanks! – neo Jun 08 '23 at 15:14
  • I applied this solution but there is generate too many crashes in firebase from users. Do you have any other solution for this? suggest me please. – Krupali Shingala Jun 23 '23 at 05:07
  • Check out my latest edit, you probably should only use it on SDK >= 34 – Niklas Jun 23 '23 at 10:11
33

Now we need to use getParcelableExtra() with the type-safer class added to API 33

SAMPLE CODE For kotlin

val userData = if (VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
  intent.getParcelableExtra("DATA", User::class.java)
} else {
  intent.getParcelableExtra<User>("DATA")
}

SAMPLE CODE For JAVA

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
  user = getIntent().getParcelableExtra("data", User.class);
} else {
  user = getIntent().getParcelableExtra("data");
}
SBotirov
  • 13,872
  • 7
  • 59
  • 81
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • I cannot make this work in Java... Could you please indicate to me what should I put instead of `User::class.java`? My code is `mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);` – Luis A. Florit Sep 10 '22 at 16:13
  • 1
    @LuisA.Florit i have updated my answer please check – AskNilesh Sep 10 '22 at 16:34
  • Thanks @AskNilesh. In the second one you meant "SAMPLE CODE For Java". In my case, it would be `KeyEvent.class` instead of `User.class`. – Luis A. Florit Sep 10 '22 at 17:23
18

androidx.core:core-ktx:1.10.0 provides IntentCompat and BundleCompat

Example for retrieving an object of android.bluetooth.BluetoothDevice:

IntentCompat.getParcelableExtra(intent, BluetoothDevice.EXTRA_DEVICE, BluetoothDevice::class.java) 
Marek Macko
  • 209
  • 2
  • 5
6

As described in the official documentation, getParcelableExtra was deprecated in API level 33.

So check if the API LEVEL is >= 33 or change the method,

...

if (Build.VERSION.SDK_INT >= 33) { // TIRAMISU
    data = intent.getParcelableExtra (String name, Class<T> clazz)
}else{
    data = intent.getParcelableExtra("")
}

Here is an example using android.bluetooth.BluetoothDevice

...
val device = if (Build.VERSION.SDK_INT >= 33){ // TIRAMISU
    intent.getParcelableArrayExtra(
        BluetoothDevice.EXTRA_NAME,
        BluetoothDevice::class.java
    )
}else{
    intent.getParcelableExtra(BluetoothDevice.EXTRA_NAME)
}
Gedeon Mutshipayi
  • 2,871
  • 3
  • 21
  • 42
6

For example, in Java:

UsbDevice device;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) { // TIRAMISU onwards
    device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, UsbDevice.class);
} else {
    device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
}

This still requires @SuppressWarnings({"deprecation", "RedundantSuppression"}).

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • It must be `TIRAMISU` (33) instead of `S_V2` (32) – MBH Oct 08 '22 at 14:56
  • 2
    @MBH no. Above code is correct. It can be `SDK_INT > S_V2` (greater than 32) or `SDK_INT >= TIRAMISU` (greater than or equal to 33). – Boken Oct 22 '22 at 15:14
  • 1
    The operator `>` suffices, because equal values are irrelevant anyway. Haven't benchmarked on JVM, but there may also be a small performance implication with the choice of operator (it doesn't matter with one iteration only): https://stackoverflow.com/a/11763604/549372 – Martin Zeitler Oct 22 '22 at 15:45
  • @Boken yeah you are right! my fault :) I always prefer putting the related sdk instead of the previous one – MBH Oct 23 '22 at 08:02