Convert Map to Bundle in android
Asked Answered
O

11

58

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.

Organon answered 26/5, 2016 at 19:13 Comment(4)
"Is there an easy way to convert a Map to a Bundle in android without explicit iteration?" -- note that a Map does not necessarily equate to a Bundle. A Map can have keys that are not strings. A Map can have values that are not one of the supported data types.Angary
Yes, but in my case they are all primitives and StringOrganon
You could serialize it.Rhizo
The RemoteMessage object is parcelable, you could just send that directly in the intentDemivolt
L
59

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());
    }
Lingonberry answered 26/5, 2016 at 20:26 Comment(2)
this will probably throw an exception because first parameter "google_sent_time" has a Long type and you are using putString. you better use the intent to handle type variation for you and use intent.putExtra(entry.getKey(), entry.getValue()) so different data types dont make problem for you.Spectrum
@AmirZiarati I don't think that is true anymore, RemoteMessage#getData() now returns a Map<String, String> excluding a bunch of the internal values.Raye
B
30

Neat Kotlin solution using spread operator will look like that:

fun Map<String, Any?>.toBundle(): Bundle = bundleOf(*this.toList().toTypedArray())
Belgravia answered 7/7, 2020 at 17:35 Comment(2)
Worth noting is that the spread operator is not the best for performance and the above solution will generate a performance warning in some static analysis tools like for example Detekt: detekt.github.io/detekt/performance.html#spreadoperatorFillender
worth mentioning that this won't create nested bundles for nested maps, in case you're using something like FIrebase Analytics that requires thatSleeping
O
16

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()
    }
  }
}
Orfinger answered 7/1, 2017 at 13:58 Comment(1)
never heard of kotlin before today; interesting findTurin
I
12

Nowadays you can use fun bundleOf(vararg pairs: Pair<String, Any?>)

Intermarriage answered 3/10, 2019 at 12:54 Comment(0)
T
1

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 here.

Trimester answered 7/9, 2016 at 5:28 Comment(3)
Parcel is a superclass of Bundle, so while it can be similarly useful, they can't be used interchangeably.Orthostichy
Yep, I did mention that it's the parent class of it.Trimester
Your answer maybe is better, but the lack of explanation or example is making it worst.Assumption
N
1

here is how I did it in Kotlin

val bundle = Bundle()

for (entry in data.entries)
    bundle.putString(entry.key, entry.value)
Nagoya answered 21/2, 2019 at 14:25 Comment(0)
W
1

In a kotlin way:

private fun Map<String, Any>.toBundle(): Bundle {
    val pairs = this.map { entry ->
        Pair(entry.key, entry.value)
    }.toTypedArray()
    return bundleOf(*pairs)
}
Wolter answered 22/2, 2023 at 16:43 Comment(0)
B
1

Here is an extention method in Kotlin:

fun Map<String, Any>.toBundle() = bundleOf(*toList().toTypedArray())
Bartonbartosch answered 19/10, 2023 at 8:29 Comment(0)
P
0

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())
Pleistocene answered 12/5, 2022 at 9:20 Comment(0)
Z
-1

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())
        }
}
Zealous answered 29/3, 2021 at 13:42 Comment(0)
P
-11
 private ArrayList<Bundle> convertMapToBundleList(ArrayList<HashMap<String, String>> mapList)
Pulpiteer answered 1/9, 2016 at 14:19 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.