如何在RxJava 2和Kotlin中将null传递给具有可空类型的Observable

问题描述 投票:10回答:4

我像这样初始化我的变量: -

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

但我不能这样做。 IDE抛出错误: -

user.onNext(null)

这样做,IDE说你永远不会为空: -

user.filter( u -> u!=null)
android kotlin rx-java rx-java2 rx-kotlin
4个回答
11
投票

正如Guenhter解释的那样,这是不可能的。但是,我建议实现Optional类型,而不是提出null-object模式:

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()

在这里使用null-object模式可能会导致比它解决的更多错误。


8
投票

如果您使用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的静态对象。

EG

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概念,并可能想到另一种解决方案,这是不需要的。


1
投票

非常感谢您的所有答案,但我最终选择了这个解决方案: -

class UserEnvelope(val user:User?) {}

并在观察中使用它。

这最符合我的要求。

我是Kotlin的新手,所以我不知道如何使用Optionals。但根据我的理解,每次我需要观察值时,我都必须将其类型化为用户类型?


0
投票

由于RxJava 2不支持空值,因此您可以使用其他一些可接受的解决方案:

  • 使用Optionals的自定义或第三方包装器库,比如一些已发布的答案建议。当我摆脱Java而不是Kotlin时,由于Kotlin本身支持可空性作为其类型系统的一部分,因此Optionals在同一个包中消失了。只是通过这种改变,代码更加清晰,我个人不希望在我的代码中返回Optionals,只要我可以避免它们。
  • 使用您的主题类型发出Any类实例。例如,您可以创建一个Empty.INSTANCE枚举类,它将模拟null值,然后按枚举类进行过滤。
  • 最后一个是我使用的,并且更喜欢作为先前解决方案的变体并且基于特化。我们的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()) }
© www.soinside.com 2019 - 2024. All rights reserved.