本文内容很简单,利用泛型简单的封装了JetPack Compose Navigation传递的参数类型,尽可能让Compose项目使用方便,维护简单。
最终效果
NavType.kt维护项目Parcelable类型参数
val TrainSettingType = SmartParcelableType(isNullableAllowed = true) { TrainingSetting::class.java }
val TrainSettingsType = SmartParcelableArrayType{ Array<TrainingSetting>::class.java }
Paths.kt
object Params {
const val TRAINING_SETTING = "trainingSetting"
}
object Paths {
const val LAUNCHER = "/launcher"
const val TRAINING = "/training/{${Params.TRAINING_SETTING}}"
// 传递对象以及对象数组的路径为/training/${Json字符串},
// 传递数组的路径为/training/[1,2,3,4,5]
// 当然还有基础数据类型
}
Routes.kt
这里的SmartXXXType最终对应的是it.arguments?.getXXX()具体实现查看下文
fun NavGraphBuilder.trainingGraph() {
composable(
Paths.TRAINING,
arguments = listOf(
navArgument(Params.TRAINING_SETTING) { type = TrainSettingType }, //Parcelable
// navArgument(Params.TRAINING_SETTING) { type = TrainSettingTypeArray }, //ParcelableArray
// navArgument(Params.TRAINING_SETTING) { type = SmartIntArrayType }, // IntArray
// navArgument(Params.TRAINING_SETTING) { type = SmartStringArrayType }, // StringArray
// navArgument(Params.TRAINING_SETTING) { type = SmartFloatArrayType }, //FloatArray
// …………
)
) {
// 对应arguments.getXXX方法
val trainingSetting = it.arguments?.getParcelable<TrainingSetting>(Params.TRAINING_SETTING)
TrainingSettingPage(trainingSetting)
}
}
SmartNavType.kt复制粘帖即用
自定义NavType从Path字符串解析参数,存入bundle
a、Parcelable和ParcelableArray通过Gson进行序列化和反序列化
b、SmartPrimitiveArrayType基础数据数组类型,解析路径/training/[1,2,3,4]路径里中括号里的内容。
class SmartParcelableType<T : Parcelable>(
isNullableAllowed: Boolean,
private val clazz: () -> Class<T>
) : NavType<T>(isNullableAllowed) {
override fun get(bundle: Bundle, key: String): T? {
return bundle.getParcelable(key)
}
override fun parseValue(value: String): T {
return Gson().fromJson(value, clazz.invoke())
}
override fun put(bundle: Bundle, key: String, value: T) {
bundle.putParcelable(key, value)
}
}
@Suppress("UNCHECKED_CAST")
class SmartParcelableArrayType<T : Parcelable>(private val clazz: () -> Class<Array<T>>) :
NavType<Array<T>>(false) {
override fun get(bundle: Bundle, key: String): Array<T>? {
return bundle.getParcelableArray(key) as? Array<T>
}
override fun parseValue(value: String): Array<T> {
return Gson().fromJson(value, clazz.invoke()) as Array<T>
}
override fun put(bundle: Bundle, key: String, value: Array<T>) {
bundle.putParcelableArray(key, value)
}
}
@Suppress("UNCHECKED_CAST")
class SmartPrimitiveArrayType<T>(private val clazz: () -> Class<T>) : NavType<T>(false) {
private fun getArrayFromKey(bundle: Bundle, key: String): T? {
return when (clazz.invoke()) {
IntArray::class.java -> bundle.getIntArray(key) as? T
FloatArray::class.java -> bundle.getFloatArray(key) as? T
BooleanArray::class.java -> bundle.getBooleanArray(key) as? T
LongArray::class.java -> bundle.getLongArray(key) as? T
DoubleArray::class.java -> bundle.getDoubleArray(key) as? T
CharArray::class.java -> bundle.getCharArray(key) as? T
ByteArray::class.java -> bundle.getByteArray(key) as? T
ShortArray::class.java -> bundle.getShortArray(key) as? T
Array<String>::class.java -> bundle.getStringArray(key) as? T
else -> null
}
}
private fun putArrayFromKeyValue(bundle: Bundle, key: String, value: T) {
when (clazz.invoke()) {
IntArray::class.java -> bundle.putIntArray(key, value as IntArray)
FloatArray::class.java -> bundle.putFloatArray(key, value as FloatArray)
BooleanArray::class.java -> bundle.putBooleanArray(key, value as BooleanArray)
LongArray::class.java -> bundle.putLongArray(key, value as LongArray)
DoubleArray::class.java -> bundle.putDoubleArray(key, value as DoubleArray)
CharArray::class.java -> bundle.putCharArray(key, value as CharArray)
ByteArray::class.java -> bundle.putByteArray(key, value as ByteArray)
ShortArray::class.java -> bundle.putShortArray(key, value as ShortArray)
Array<String>::class.java -> bundle.putStringArray(
key,
value as Array<out String>
) as? T
else -> {
// ignore
}
}
}
private fun parseValueFromString(paramsString: String): T {
val params = paramsString.replace("[", "").replace("]", "").split(",")
when (clazz.invoke()) {
IntArray::class.java -> {
return IntArray(params.size) {
params[it].toInt()
} as T
}
FloatArray::class.java -> {
return FloatArray(params.size) {
params[it].toFloat()
} as T
}
BooleanArray::class.java -> {
return BooleanArray(params.size) {
params[it].toBoolean()
} as T
}
LongArray::class.java -> {
return LongArray(params.size) {
params[it].toLong()
} as T
}
DoubleArray::class.java -> {
return DoubleArray(params.size) {
params[it].toDouble()
} as T
}
CharArray::class.java -> {
return CharArray(params.size) {
params[it][0]
} as T
}
ByteArray::class.java -> {
return ByteArray(params.size) {
params[it].toByte()
} as T
}
ShortArray::class.java -> {
return ShortArray(params.size) {
params[it].toShort()
} as T
}
Array<String>::class.java -> {
return params.toTypedArray() as T
}
else -> {
throw IllegalArgumentException("SmartArrayType can not support this type !!!")
}
}
}
override fun get(bundle: Bundle, key: String): T? {
return getArrayFromKey(bundle, key)
}
override fun parseValue(value: String): T {
return parseValueFromString(value)
}
override fun put(bundle: Bundle, key: String, value: T) {
putArrayFromKeyValue(bundle, key, value)
}
}
val SmartIntArrayType = SmartPrimitiveArrayType { IntArray::class.java }
val SmartFloatArrayType = SmartPrimitiveArrayType { FloatArray::class.java }
val SmartBooleanArrayType = SmartPrimitiveArrayType { BooleanArray::class.java }
val SmartLongArrayType = SmartPrimitiveArrayType { LongArray::class.java }
val SmartDoubleArrayType = SmartPrimitiveArrayType { DoubleArray::class.java }
val SmartCharArrayType = SmartPrimitiveArrayType { CharArray::class.java }
val SmartByteArrayType = SmartPrimitiveArrayType { ByteArray::class.java }
val SmartShortArrayType = SmartPrimitiveArrayType { ShortArray::class.java }
val SmartStringArrayType = SmartPrimitiveArrayType { Array<String>::class.java }
val SmartFloatType = NavType.FloatType
val SmartIntType = NavType.IntType
val SmartBooleanType = NavType.BoolType
val SmartStringType = NavType.StringType
处理Path数组参数拼接,对象使用gson转json串和基础数据类型直接转String
private val gson = Gson()
fun arrayToPath(value: Array<*>): String {
return value.joinToString(",", prefix = "[", postfix = "]", transform = {
if (it is String) return@joinToString it
if (it is Parcelable) return@joinToString gson.toJson(it)
return@joinToString it.toString()
})
}
Over!