Kotlin Android泛型处理SharedPreferences时Long与Int类型异常问题
问题分析与解决思路
你的问题核心在于泛型类型推断错误,导致preferenceValueFlow函数走到了Int类型的分支,而非预期的Long分支,最终引发NumberFormatException。以下是具体原因和解决步骤:
根本原因
当你调用getPreferenceAsFlow("key", null)并指定变量类型为Flow<Long?>时,由于默认值null没有明确的类型信息,加上T::class无法区分可空类型(Long?的KClass与Long的KClass是同一个实例),运行时泛型擦除可能导致类型判断逻辑匹配错误,最终执行了getInteger方法。如果存储的是超出Int范围的Long值,就会触发数字格式异常。
解决步骤
1. 显式指定泛型参数
调用时显式传递泛型类型,避免编译器模糊推断:
val lastAppDataUpdateDate: Flow<Long?> = securePrefs.getPreferenceAsFlow<Long?>("key", null)
2. 改进类型判断逻辑(推荐方案)
使用reified泛型结合typeOf(需依赖kotlin-reflect),可以准确识别可空与非空类型,避免匹配错误:
首先添加kotlin-reflect依赖(Gradle):
implementation "org.jetbrains.kotlin:kotlin-reflect:1.9.20"
然后修改preferenceValueFlow函数:
@Suppress("UNCHECKED_CAST") private inline fun <reified T> preferenceValueFlow(keyValue: String, defValue: T?): T? { return when (typeOf<T>()) { typeOf<String>(), typeOf<String?>() -> getString(key = keyValue, defValue as String?) as T? typeOf<Boolean>(), typeOf<Boolean?>() -> getBoolean(key = keyValue, defValue ?: false) as T? typeOf<Int>(), typeOf<Int?>() -> getInteger(key = keyValue, defValue as Int?) as T? typeOf<Long>(), typeOf<Long?>() -> getLong(key = keyValue, defValue as Long?) as T? else -> throw IllegalArgumentException("Preference type not supported: ${typeOf<T>().typeName}") } }
3. 无反射依赖的替代方案
如果不想引入kotlin-reflect,可以通过默认值的类型辅助判断,同时保留泛型显式指定:
@Suppress("UNCHECKED_CAST") private fun <T> preferenceValueFlow(keyValue: String, defValue: T?): T? { // 优先用默认值的类型,默认值为null时依赖泛型推断的类型 val targetClass = defValue?.let { it::class } ?: T::class return when (targetClass) { String::class -> getString(key = keyValue, defValue as String?) as T? Boolean::class -> getBoolean(key = keyValue, defValue?.let { it as Boolean } ?: false) as T? Int::class -> getInteger(key = keyValue, defValue as Int?) as T? Long::class -> getLong(key = keyValue, defValue as Long?) as T? else -> throw IllegalArgumentException("Preference type not supported: ${targetClass.java.name}") } }
4. 验证存储类型一致性
确认存储该key时使用的是putLong(或对应的加密存储方法),而非putInt。如果存储的是Int类型值,即使读取为Long,超出Int范围时仍会引发异常。
内容的提问来源于stack exchange,提问作者Agustin Sivoplás
相关产品推荐
相关产品推荐

