I am passing data via intent with Parcelable and receiving using getParcelableExtra . However getParcelableExtra seems to be deprecated, How do I fix the deprecation warning in this code? Alternatively, are there any other options for doing this? . I am using compileSdkVersion 33.
Code snippet:
var data = intent.getParcelableExtra("data")
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)
}
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 >= 33) {
intent.getParcelableExtra("DATA", User::class.java)
} else {
intent.getParcelableExtra<User>("DATA")
}
SAMPLE CODE For JAVA
if (android.os.Build.VERSION.SDK_INT >= 33) {
user = getIntent().getParcelableExtra("data", User.class);
} else {
user = getIntent().getParcelableExtra("data");
}
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"}).
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) {
data = intent.getParcelableExtra (String name, Class<T> clazz)
}else{
data = intent.getParcelableExtra("data")
}
Related
I want to use intent method for get uri from another activity, but intent.getParcelableExtra is deprecated.if I use
if (SDK_INT >= 33) {
intent.getParcelableExtra("EXTRA_URI", Uri::class.java).let { ueray ->
timeLineView.post({
if (ueray != null) {
setBitmap(ueray)
videoView.setVideoURI(ueray)
}
})
}
}
else {
#Suppress("DEPRECATION")
intent.getParcelableExtra<Uri>("EXTRA_URI").let { ueray ->
timeLineView.post({
if (ueray != null) {
setBitmap(ueray)
videoView.setVideoURI(ueray)
}
})
}
}
this code can google play reject my app? because when in remove (SDK_INT >= 33) statement it shows
Call requires API level 33 (current min is 21): android.content.Intent#getParcelableExtra. Thanks in advance
No, Google will not reject your app if you use deprecated method, especially when using it is a necessity as you have no other choice than to use it on SDK's < 33.
My app uses deprecated methods on lower SDK's when it is an only possibility and the app is fine and accessible on the Google Play Store:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val vibrationEffect = VibrationEffect.createWaveform(
longArrayOf(1000, 1000),
intArrayOf(255, 0),
0
)
vibrator.vibrate(vibrationEffect, vibrationAudioAttributes)
} else {
// deprecated but working on lower SDK's
vibrator.vibrate(longArrayOf(0, 1000, 1000), 0, vibrationAudioAttributes)
}
These are extension functions for Intent and they are backward compatible:
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Intent.getParcelable(key: String): P? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableExtra(key, P::class.java)
} else {
getParcelableExtra(key)
}
}
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Intent.getParcelableArrayList(key: String): ArrayList<P>? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableArrayListExtra(key, P::class.java)
} else {
getParcelableArrayListExtra(key)
}
}
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Bundle.getParcelableValue(key: String): P? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelable(key, P::class.java)
} else {
getParcelable(key)
}
}
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Bundle.getParcelableArrayListValue(key: String): ArrayList<P>? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableArrayList(key, P::class.java)
} else {
getParcelableArrayList(key)
}
}
Instead of the uri put uri.toString() as an extra string.
Quite simple.
Starting from API level 33 the getPackageInfo(String, int) method of PackageManager class is deprecated. Documentation suggests to use getPackageInfo(String, PackageInfoFlags) instead. But that function is only available from API level 33.
My current code:
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
Is this how it should be now?
val pInfo = context.getPackageInfo()
#Suppress("DEPRECATION")
fun Context.getPackageInfo(): PackageInfo {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
} else {
packageManager.getPackageInfo(packageName, 0)
}
}
If you are using Kotlin, you can add extension function to your project:
fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): PackageInfo =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags.toLong()))
} else {
#Suppress("DEPRECATION") getPackageInfo(packageName, flags)
}
and after just call packageManager.getPackageInfoCompat(packageName) or add another flag, if you need.
Is this how it should be now?
Yes, though I've gotten out of the practice of using TIRAMISU in favor of the actual underlying Int.
Ideally, Google would add stuff to PackageManagerCompat for these changes, and perhaps they will now that Android 13 is starting to ship to users.
Im my current Android application i am trying to implement the following extension functions to handle any type of intent extra
fun Activity.extraNotNull(key: String): Lazy<String> = lazy {
val value: String? = intent?.extras?.getString(key)
requireNotNull(value) { MISSING_MANDATORY_KEY + key }
}
fun Activity.extraNotNull(key: String): Lazy<Long> = lazy {
val value: Long? = intent?.extras?.getLong(key)
requireNotNull(value) { MISSING_MANDATORY_KEY + key }
}
however i am getting the following compile time error
how can i resolve the conflicting overloads error
As mentioned its not possible to overload methods with identical signatures and different return types - there is no way to differentiate what method you are calling.
A better solution is to make generic function that would support all types, something like this would be a good starting point :
inline fun <reified T> Activity.extraNotNull(key: String): Lazy<T> = lazy {
val value: T? = intent?.extras?.let { x ->
when (T::class) {
String::class -> x.getString(key)
Long::class -> x.getLong(key)
Float::class -> x.getFloat(key)
Double::class -> x.getDouble(key)
else -> throw IllegalArgumentException("not a valid data type ${T::class}")
} as? T
}
requireNotNull(value)
}
Usage :
val s: String by extraNotNull("a")
val l: Long by extraNotNull("b")
val f: Float by extraNotNull("c")
val d: Double by extraNotNull("d")
You can't do that. Method overloading won't work if you only change the return type. You need to add/remove some of the parameters.
I have written a simple Statment like this:
val installer = context.packageManager.getInstallerPackageName(context.packageName)
but it's now deprecated as shown in the picture:
Is there any alternative way available to get the package name of the app that has installed your app?
Here's how you can use the new one:
fun getInstallerPackageName(context: Context, packageName: String): String? {
kotlin.runCatching {
if (VERSION.SDK_INT >= VERSION_CODES.R)
return context.packageManager.getInstallSourceInfo(packageName).installingPackageName
#Suppress("DEPRECATION")
return context.packageManager.getInstallerPackageName(packageName)
}
return null
}
I created a helper function to check the remaining space of any given directory.
#RequiresApi(Build.VERSION_CODES.O)
fun Context.hasFreeSpace(directory: File, requiredStorageSpace: Long): Boolean{
return try {
val storageManager = getSystemService<StorageManager>()
val directoryUUID = storageManager!!.getUuidForPath(directory)
val availableBytes = storageManager.getAllocatableBytes(directoryUUID)
availableBytes > requiredStorageSpace
}catch (e: Exception){
e.printStackTrace()
false
}
}
Follow this link actually.
https://developer.android.com/training/data-storage/app-specific#query-free-space
The problem is I get storageManager!!.getUuidForPath and storageManager.getAllocatableBytes both require for API >= 26.
I did google around but not thing came back on how to get the directory's UUID on API < 26.
Does anyone have any idea how to achieve that?
Thanks
Well, I guess I need a different approach. As I googled, UUID required was added when Android O was released. So basically, no such thing gets directory UUID exits before O. This is my helper function now.
#SuppressLint("NewApi")
fun Context.hasFreeSpace(directory: File, requiredStorageSpace: Long): Boolean {
return try {
val api = Build.VERSION.SDK_INT
val availableBytes = when {
api >= Build.VERSION_CODES.O -> {
val storageManager = getSystemService<StorageManager>()
val directoryUUID = storageManager!!.getUuidForPath(directory)
storageManager.getAllocatableBytes(directoryUUID)
}
else -> {
val stat = StatFs(directory.path)
stat.availableBlocksLong * stat.blockSizeLong
}
}
availableBytes > requiredStorageSpace
} catch (e: Exception) {
e.printStackTrace()
false
}
}