que*_*zak 8 java android kotlin firebase firebase-realtime-database
我在firebase上的数据使用了许多具有字符串类型的字段,但实际上是枚举值(我在验证规则中检查).要按照指南将数据下载到我的Android应用程序中,该字段必须是基本字段String.我知道我可以使用枚举的第二个(排除的)字段解决这个问题,并根据字符串值设置此字段.一个简短的例子:
class UserData : BaseModel() {
val email: String? = null
val id: String = ""
val created: Long = 0
// ... more fields omitted for clarity
@Exclude
var weightUnitEnum: WeightUnit = WeightUnit.KG
var weightUnit: String
get() = weightUnitEnum.toString()
set(value) { weightUnitEnum = WeightUnit.fromString(value) }
}
enum class WeightUnit(val str: String) {
KG("kg"), LB("lb");
override fun toString(): String = str
companion object {
@JvmStatic
fun fromString(s: String): WeightUnit = WeightUnit.valueOf(s.toUpperCase())
}
}
Run Code Online (Sandbox Code Playgroud)
现在,虽然这有效,但它并不是很干净:
enum class本身是(1)有点长的枚举,(2)内部重复每个枚举.而且我有更多.created上面的字段实际上是一个时间戳,而不是一个Long.Map<SomeEnum, Timestamp>...那么,有没有办法正确地做到这一点?有些图书馆可能?或者某种方式来编写一个神奇的"字段包装器",它会自动将字符串转换为枚举,或者数字转换为时间戳,等等,但仍然与Firebase库兼容以获取/设置数据?
(也欢迎Java解决方案:))
如果具有您的enum值的属性与另一个String类型属性之间的转换足够,则可以使用Kotlin委派属性以灵活的方式轻松完成此操作.
简而言之,您可以为String执行转换的属性实现委托,并实际获取/设置存储值的另一个属性的enum值,然后将String属性委托给它.
一种可能的实现方式如下:
class EnumStringDelegate<T : Enum<T>>(
private val enumClass: Class<T>,
private val otherProperty: KMutableProperty<T>,
private val enumNameToString: (String) -> String,
private val stringToEnumName: (String) -> String) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return enumNameToString(otherProperty.call(thisRef).toString())
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
val enumValue = java.lang.Enum.valueOf(enumClass, stringToEnumName(value))
otherProperty.setter.call(thisRef, enumValue)
}
}
Run Code Online (Sandbox Code Playgroud)
注意:此代码要求您将Kotlin反射API添加kotlin-reflect为项目的依赖项.使用Gradle,使用compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version".
这将在下面解释,但首先让我添加一个方便的方法,以避免直接创建实例:
inline fun <reified T : Enum<T>> enumStringLowerCase(
property: KMutableProperty<T>) = EnumStringDelegate(
T::class.java,
property,
String::toLowerCase,
String::toUpperCase)
Run Code Online (Sandbox Code Playgroud)
以及您班级的使用示例:
// if you don't need the `str` anywhere else, the enum class can be shortened to this:
enum class WeightUnit { KG, LB }
class UserData : BaseModel() {
// ... more fields omitted for clarity
@Exclude
var weightUnitEnum: WeightUnit = WeightUnit.KG
var weightUnit: String by enumStringLowerCase(UserData::weightUnitEnum)
}
Run Code Online (Sandbox Code Playgroud)
现在,解释:
编写时var weightUnit: String by enumStringLowerCase(UserData::weightUnitEnum),将String属性委托给构造的委托对象.这意味着在访问属性时,将调用委托方法.然后,委托对象与weightUnitEnum引擎盖下的属性一起工作.
我添加的便利功能使您免于UserData::class.java在属性声明站点上写入的必要性(使用reified类型参数)并提供转换函数EnumStringDelegate(您可以随时创建具有不同转换的其他函数,甚至可以创建一个接收的函数)转换函数为lambdas).
基本上,这个解决方案可以节省您的样板代码,该代码表示enum类型属性作为String属性,给定转换逻辑,并且enum如果您不在其他任何地方使用它,也可以让您摆脱您的冗余代码.
使用此技术,您可以实现属性之间的任何其他转换,例如您提到的时间戳编号.
小智 5
我处于类似的情况,因此找到了您的问题,以及许多其他类似的问题/答案。
无法直接回答您的问题,但这就是我最终做的:我决定更改我的应用程序并且根本不使用枚举数据类型 - 主要是因为 Google 开发门户的建议显示了枚举对应用程序性能的影响。请参阅下面的视频https://www.youtube.com/watch?v=Hzs6OBcvNQE
| 归档时间: |
|
| 查看次数: |
1536 次 |
| 最近记录: |