KotlinでLiveDataを使用し、nullにしないでください。これにどう対処しますか?おそらくLiveDataのラッパーですか?ここで良いパターンを検索しています..例として:
class NetworkDefinitionProvider : MutableLiveData<NetworkDefinition>() {
val allDefinitions = mutableListOf(RinkebyNetworkDefinition(), MainnetNetworkDefinition(), RopstenNetworkDefinition())
init {
value = allDefinitions.first()
}
fun setCurrent(value: NetworkDefinition) {
setValue(value)
}
}
アクセス時に値がnullにならないことはわかっていますが、常にnullをチェックするか、これらの醜い!!を使用する必要があります。
拡張プロパティを作成しました。それはとてもきれいではありませんが、isはかなり簡単です。
val <T> LiveData<T>.valueNN
get() = this.value!!
使用法
spinner.loading = myLiveData.valueNN.homeState.loading
「NN」を適切な命名規則として追加することはできませんが、それは質問の範囲を超えています:)
私は少し改善します answer ラッキーコーダー。この実装はnull値をまったく受け入れることができません。
class NonNullMutableLiveData<T: Any>(initValue: T): MutableLiveData<T>() {
init {
value = initValue
}
override fun getValue(): T {
return super.getValue()!!
}
override fun setValue(value: T) {
super.setValue(value)
}
fun observe(owner: LifecycleOwner, body: (T) -> Unit) {
observe(owner, Observer<T> { t -> body(t!!) })
}
override fun postValue(value: T) {
super.postValue(value)
}
}
これが最善の解決策かどうかはわかりませんが、これが私が思いついたものであり、私が使用しているものです。
class NonNullLiveData<T>(private val defaultValue: T) : MutableLiveData<T>() {
override fun getValue(): T = super.getValue() ?: defaultValue
fun observe(owner: LifecycleOwner, body: (T) -> Unit) {
observe(owner, Observer<T> {
body(it ?: defaultValue)
})
}
}
フィールドを作成する:
val string = NonNullLiveData("")
そしてそれを観察する:
viewModel.string.observe(this) {
// Do someting with the data
}
LifecycleOwnerの拡張機能を作成できます
fun <T> LifecycleOwner.observe(liveData: LiveData<T?>, lambda: (T) -> Unit) {
liveData.observe(this, Observer { if (it != null) lambda(it) })
}
そしてあなたのフラグメント/アクティビティで
observe(liveData) { ... }
あなたはこれを行うことができます
normalLiveData
.nonNull()
.observe(this, { result ->
// result is non null now
})
それに関する記事があります。 https://medium.com/@henrytao/nonnull-livedata-with-kotlin-extension-26963ffd03
私は本当に The Lucky Coder の答えが好きでした。 null値を設定しようとすることの危険性に関して、私はこれに対して例外をスローする必要があると思います(何が David Whitman が指しているのと同様):
class NonNullLiveData<T>(private val defaultValue: T) : MutableLiveData<T>() {
override fun getValue(): T = super.getValue() ?: defaultValue
override fun setValue(value: T) {
if(value != null) {
super.setValue(value)
}
else throw IllegalArgumentException("Cannot set a null value to this Type. Use normal MutableLiveData instead for that.")
}
override fun postValue(value: T) {
if(value != null) {
super.postValue(value)
}
else throw IllegalArgumentException("Cannot post a null value to this Type. Use normal MutableLiveData instead for that.")
}
fun observe(owner: LifecycleOwner, body: (T) -> Unit) {
observe(owner, Observer<T> {
body(it ?: defaultValue)
})
}
}
これで、MutableLiveDataの値がnullになることはないため、クラスが意図しない方法で使用されることはありません。
文字列を使用する場合、この方法を使用すると簡単です。
val someLiveData = MutableLiveData<String>()
...
someLiveData.value.orEmpty()
そして、設定されている場合は実際の値、またはnull
の代わりに空の文字列を取得します。
これが私の解決策です。
class NotNullLiveData<T : Any>
constructor(private val default: T) : MediatorLiveData<T>() {
override fun getValue(): T {
return super.getValue() ?: default
}
override fun setValue(value: T) {
super.setValue(value)
}
}
@MainThread
fun <T : Any> mutableLiveDataOfNotNull(initValue: T): NotNullLiveData<T> {
val liveData = NotNullLiveData(initValue)
liveData.value = initValue
return liveData
}
@MainThread
fun <T> mutableLiveDataOf(initValue: T): MutableLiveData<T> {
val liveData = MutableLiveData<T>()
liveData.value = initValue
return liveData
}
fun <T : Any> LiveData<T?>.toNotNull(default: T): NotNullLiveData<T> {
val result = NotNullLiveData(default)
result.addSource(this) {
result.value = it ?: default
}
return result
}