有没有一种简单的方法可以在不进行显式迭代的情况下将Map转换为Android中的Bundle?
为什么这样做?
Firebase返回Notification getData()
的Map格式数据。我需要将这些数据传递给一个intent。以前GCM会返回bundle,因此我不需要担心这个问题。
有没有一种简单的方法可以在不进行显式迭代的情况下将Map转换为Android中的Bundle?
为什么这样做?
Firebase返回Notification getData()
的Map格式数据。我需要将这些数据传递给一个intent。以前GCM会返回bundle,因此我不需要担心这个问题。
我想一个传统的for循环是最简单的方法:
Bundle bundle = new Bundle();
for (Map.Entry<String, String> entry : getData().entrySet()) {
bundle.putString(entry.getKey(), entry.getValue());
}
putString
,所以可能会引发异常。您最好使用intent来处理类型变化,并使用intent.putExtra(entry.getKey(), entry.getValue())
,这样不同的数据类型就不会为您带来问题。 - Amir ZiaratiRemoteMessage#getData()
现在返回一个Map<String, String>
,排除了许多内部值。 - Mikael Ohlson使用展开运算符的简洁 Kotlin 解决方案将如下所示:
fun Map<String, Any?>.toBundle(): Bundle = bundleOf(*this.toList().toTypedArray())
我在使用 Firebase Messaging 时遇到了同样的问题,并创建了一个 Kotlin 扩展函数解决它。这里是 gist,以下是代码。虽然我在使用这种方法,但还有一些注意事项:
请记住这一点,将其用作指南而不是最终解决方案。随着它的演变,我会保持 gist 最新。
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()
}
}
}
现在你可以使用fun bundleOf(vararg pairs: Pair<String, Any?>)
您可以使用writeToParcel(Parcel out, int flags)
方法生成一个Parcel
对象,这个对象与Bundle
类似,而且它是RemoteMessage
类的一部分,方便地内置于Firebase框架中。相关文档在此。
Parcel
是 Bundle
的超类,因此它们可能同样有用,但不能互换使用。 - Pierre-Luc Paourval bundle = Bundle()
for (entry in data.entries)
bundle.putString(entry.key, entry.value)
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val payload = remoteMessage.data.toBundle()
Log.d(TAG, "Notification payload: $payload")
// ...
}
toBundle() 的定义如下:
inline fun <reified T> Map<String, T>.toBundle(): Bundle = bundleOf(*toList<String, T?>().toTypedArray())
或者再次:
inline fun <reified T> Map<String, T>.toBundle(): Bundle = bundleOf(*map { it.key to it.value }.toTypedArray())
private fun Map<String, Any>.toBundle(): Bundle {
val pairs = this.map { entry ->
Pair(entry.key, entry.value)
}.toTypedArray()
return bundleOf(*pairs)
}
fun Map<String, Any>.toBundle() = bundleOf(*toList().toTypedArray())
供日后参考
将Map转换为字符串
fun Map<String, String>.convertExtraMapToString(): String? {
return keys.stream()
.map { key: String -> "$key=" + this[key] }.collect(Collectors.joining(", ", "{", "}"))
}
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())
}
}