Convert Map to Bundle in android
AndroidFirebaseBundleFirebase Cloud-MessagingAndroid Problem Overview
Is there an easy way to convert a Map to a Bundle in android without explicit iteration?
Why?
Firebase returns a Map for Notification getData()
. I need to pass the data to an intent. Formerly GCM gave me a bundle, so I didn't need to worry about this.
Android Solutions
Solution 1 - Android
I guess a good old fashioned for loop is the easiest way:
Bundle bundle = new Bundle();
for (Map.Entry<String, String> entry : getData().entrySet()) {
bundle.putString(entry.getKey(), entry.getValue());
}
Solution 2 - Android
Neat Kotlin solution using spread operator will look like that:
fun Map<String, Any?>.toBundle(): Bundle = bundleOf(*this.toList().toTypedArray())
Solution 3 - Android
Came across this same issue with firebase messaging and created a kotlin extension function for it. The gist is here, code below. Although I am using this method there are some caveats:
- it doesn't cover all of the types that can be put into a bundle
- it is still under development and hasn't been fully tested
With this in mind, please use it as a guide not a definitive solution. I will keep the gist up to date as it evolves.
import android.os.Bundle
import android.os.IBinder
import android.os.Parcelable
import java.io.Serializable
fun <V> Map<String, V>.toBundle(bundle: Bundle = Bundle()): Bundle = bundle.apply {
forEach {
val k = it.key
val v = it.value
when (v) {
is IBinder -> putBinder(k, v)
is Bundle -> putBundle(k, v)
is Byte -> putByte(k, v)
is ByteArray -> putByteArray(k, v)
is Char -> putChar(k, v)
is CharArray -> putCharArray(k, v)
is CharSequence -> putCharSequence(k, v)
is Float -> putFloat(k, v)
is FloatArray -> putFloatArray(k, v)
is Parcelable -> putParcelable(k, v)
is Serializable -> putSerializable(k, v)
is Short -> putShort(k, v)
is ShortArray -> putShortArray(k, v)
// is Size -> putSize(k, v) //api 21
// is SizeF -> putSizeF(k, v) //api 21
else -> throw IllegalArgumentException("$v is of a type that is not currently supported")
// is Array<*> -> TODO()
// is List<*> -> TODO()
}
}
}
Solution 4 - Android
Nowadays you can use fun bundleOf(vararg pairs: Pair<String, Any?>)
Solution 5 - Android
You can use writeToParcel(Parcel out, int flags)
to generate a Parcel
that could be similarly useful, since it's a parent class of Bundle
, and it's handily built into the Firebase framework as part of the RemoteMessage
class. Documentation is https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/RemoteMessage.html#writeToParcel(android.os.Parcel, int)">here.
Solution 6 - Android
here is how I did it in Kotlin
val bundle = Bundle()
for (entry in data.entries)
bundle.putString(entry.key, entry.value)
Solution 7 - Android
In Kotlin you can build a function extension to convert Map to Bundle without explicit iteration like so:
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val payload = remoteMessage.data.toBundle()
Log.d(TAG, "Notification payload: $payload")
// ...
}
where toBundle() is defined like so:
inline fun <reified T> Map<String, T>.toBundle(): Bundle = bundleOf(*toList<String, T?>().toTypedArray())
or again:
inline fun <reified T> Map<String, T>.toBundle(): Bundle = bundleOf(*map { it.key to it.value }.toTypedArray())
Solution 8 - Android
For future reference
> Convert Map to String
fun Map<String, String>.convertExtraMapToString(): String? {
return keys.stream()
.map { key: String -> "$key=" + this[key] }.collect(Collectors.joining(", ", "{", "}"))
}
> Convert String to Map then to Bundle
fun String.convertExtraMapToBundle(): Bundle {
return Arrays.stream(split(",".toRegex()).toTypedArray())
.map { entry: String -> entry.split("=".toRegex()).toTypedArray() }
.collect(Collectors.toMap(
{ entry: Array<String> -> entry[0] }) { entry: Array<String> -> entry[1] }).let {
bundleOf(*it.toList().toTypedArray())
}
}
Solution 9 - Android
private ArrayList<Bundle> convertMapToBundleList(ArrayList<HashMap<String, String>> mapList)