web-dev-qa-db-ja.com

RxJava 2およびKotlinでnull許容型のObservableにnullを渡す方法

このように変数を初期化します:

 val user: BehaviorSubject<User?> user = BehaviorSubject.create()

しかし、私はこれを行うことはできません。 IDEはエラーをスローします:-

user.onNext(null)

そして、これを行うと、IDEはuが決してnullにならないことを示します:-

user.filter( u -> u!=null)
13
Abhinav Nair

あなたのすべての答えに感謝しますが、私は最終的にこの解決策に行きました:-

class UserEnvelope(val user:User?) {}

そして、オブザーバブルでこれを使用します。

これは私の要件に最適です。

私はKotlinが初めてなので、オプションの使用方法がわかりません。しかし、私が理解していることから、値を正しく観察する必要があるたびに、ユーザータイプに型キャストする必要がありますか?

1
Abhinav Nair

Guenhter が説明したように、これは不可能です。ただし、nullオブジェクトパターンを提案する代わりに、Optional型の実装をお勧めします。

data class Optional<T>(val value: T?)
fun <T> T?.asOptional() = Optional(this)

これにより、意図がより明確になり、関数内で構造化宣言を使用できます。

Observable.just(Optional("Test"))
  .map { (text: String?) -> text?.substring(1)?.asOptional() }
  .subscribe()

ここでヌルオブジェクトパターンを使用すると、解決するよりも多くのバグが発生する可能性があります。

11
nhaarman

Rxkotlin/rxjava 2.0(私はそう思う)を使用する場合、答えは「できない」です。その理由をここで説明します。

これはインターフェースの中断です。 Observableインターフェイスをご覧ください

public interface Observer<T> {

    /** ... */
    void onSubscribe(@NonNull Disposable d);

    /** ... */
    void onNext(@NonNull T t);

    /** ... */
    void onError(@NonNull Throwable e);

    /** ... */
    void onSubscribe(@NonNull Disposable d);

    /** ... */
    void onNext(@NonNull T t);

    /** ... */
    void onError(@NonNull Throwable e);
...

@NonNullはKotlinコンパイラによって考慮されるため、nullを渡すことはできません。

できたとしても、onNextはすぐにエラーをスローします:

@Override
public void onNext(T t) {
    if (t == null) {
        onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
        return;
    }
    ...
}

nullのようなものが本当に必要な場合は、それを偽造する必要があります。例えばUser要素を表すnullの静的オブジェクトを作成します。

例えば.

data class User(val username, val password) {

    companion object {
        val NULL_USER = User("", "")
    }
}
...
val user = BehaviorSubject.create<User>()
...
user.onNext(User.NULL_USER)
...
user.filter { it !== User.NULL_USER }

しかし、それはどういうわけか可能です。nullの概念を避け、これが不要な別のソリューションを考えてみてください。

8
guenhter

RxJava 2はnull値をサポートしていないため、使用できる他の解決策がいくつかあります。

  • 投稿された回答のいくつかが示唆するように、オプションのカスタムまたはサードパーティのラッパーライブラリを操作します。 Kotlinを支持してJavaを取り除きましたが、Kotlin自体がその型Systemの一部としてnullabilityをサポートしているため、Optionalsは同じパッケージでなくなりました。この変更により、コードはより明確になりました、そして、私はそれらを避けることができる限り、私のコードでオプションを取り戻したくありません。
  • サブジェクトタイプでAnyクラスインスタンスを生成します。たとえば、Empty.INSTANCE enumクラス。null値をエミュレートし、enumクラスでフィルタリングします。
  • 最後の1つは、私が使用しているもので、以前のソリューションのバリアントであることを好み、専門分野に基づいています。 JetBrainsの友人は、Kotlinのクラスは非常に安価であることを常に強調しているため、これはログに記録されたユーザーとログに記録されていないユーザーを区別する簡単な例です。

    abstract class SessionUser
    sealed class LoggedUser(val username: String, val password: String) : SessionUser()
    sealed class LogoutUser : SessionUser()
    
    private val user = BehaviorSubject.create<SessionUser>()
    private val loggedUser = 
       user.filter { it is LoggedUser }.cast(LoggedUser::class.Java)
    
    fun login(username: String, password: String) {
       user.onNext(LoggedUser(username, password))
    }
    
    fun logout() {
       user.onNext(LogoutUser())
    }
    
0
GoRoS