21

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

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

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

user.onNext(null)

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

user.filter( u -> u!=null)
4

7 回答 7

25

正如Guenhter解释的那样,这是不可能的。但是,我建议使用该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()

在这里使用空对象模式可能会导致比它解决的更多的错误。

于 2017-07-25T11:47:09.647 回答
11

如果您使用 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);
...

Kotlin 编译器@NonNull将考虑它,因此您不能传递 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概念,也许考虑另一种不需要的解决方案。

于 2017-07-25T05:36:13.000 回答
3

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

class UserEnvelope(val user:User?) {}

并在 observables 中使用它。

这最适合我的要求。

我是 Kotlin 的新手,所以我不知道如何使用 Optionals。但是据我了解,每次我需要观察这些值时,我都必须将其类型转换为用户类型,对吗?

于 2017-07-28T10:33:32.030 回答
1

要实现nhaarman的答案中提到的解决方案,您可以使用API 级别 24中添加的 Android SDK 中的 util 类Optionaldoc ) 。

如果您的应用程序minSdkVersion小于 24,那么您仍然需要自己实现它。

于 2020-02-06T12:13:12.540 回答
0

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

  • 使用自定义或第三方的 Optionals 包装库,就像一些已发布的答案所建议的那样。当我摆脱 Java 转而支持 Kotlin 时,Optionals 在同一个包中消失了,因为 Kotlin 本身支持可空性作为其类型 System 的一部分。只是通过这种更改,代码更加清晰,我个人不想让 Optionals 回到我的代码中,只要我可以避免它们。
  • 使用您的主题类型发出Any类实例。例如,您可以创建一个Empty.INSTANCE模拟值的枚举类,然后按枚举类进行过滤。
  • 最后一个是我使用的一个,并且更喜欢成为先前解决方案的变体,并且基于专业化。我们的 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())
    }
    
于 2018-05-25T19:23:23.513 回答
0

我采取了类似于Optional<User>and的方法UserEnvelope。我创建了一个简单的User类和一个ReifiedUser继承自它的类。该类Usercompanion object一个 NONE 实例。用实例实例BehaviorSubjectUser.NONE。它看起来像这样:

open class User {
    companion object {
        val NONE = User()
    }
}

class ReifiedUser(
        @field:JsonProperty(J.FirstName) val firstName: String,
        @field:JsonProperty(J.LastName) val lastName: String
) : User()

BehaviorSubject的实例化如下:

val activeUser: BehaviorSubject<User> = BehaviorSubject.createDefault(User.NONE)

无论我需要在哪里使用activeUserflatMapObservable.empty()如果它是 NONE 或者只是弄清楚它是什么以及在订阅者中做什么。

我不喜欢将 javaOptional与可空的 kotlin 混合,因为混合maplet变得非常混乱和丑陋。这样一来,发生的事情就很明显了。

于 2020-10-27T22:20:18.183 回答
0

我认为编写一个容器类(例如Result. 一个例子是

data class Result<T>(value: T?, error: Throwable?)

用法

Observable.create { observer ->
   upstreamService.listen(object: UpstreamListener {
     onSuccess(data: User) {
       observer.onSuccess(Result(data))
     }
     onError(exception: Throwable) {
       observer.onSuccess(Result(null, exception))
     }
   }
}
于 2021-04-06T14:54:39.507 回答