我像这样初始化我的变量:-
val user: BehaviorSubject<User?> user = BehaviorSubject.create()
但我不能这样做。IDE 抛出错误:-
user.onNext(null)
这样做,IDE 说你永远不会为空:-
user.filter( u -> u!=null)
正如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()
在这里使用空对象模式可能会导致比它解决的更多的错误。
如果您使用 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
概念,也许考虑另一种不需要的解决方案。
非常感谢您的所有回答,但我最终选择了这个解决方案:-
class UserEnvelope(val user:User?) {}
并在 observables 中使用它。
这最适合我的要求。
我是 Kotlin 的新手,所以我不知道如何使用 Optionals。但是据我了解,每次我需要观察这些值时,我都必须将其类型转换为用户类型,对吗?
要实现nhaarman的答案中提到的解决方案,您可以使用API 级别 24中添加的 Android SDK 中的 util 类Optional
(doc ) 。
如果您的应用程序minSdkVersion
小于 24,那么您仍然需要自己实现它。
由于 RxJava 2 不支持null值,因此您可以使用其他一些可接受的解决方案:
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())
}
我采取了类似于Optional<User>
and的方法UserEnvelope
。我创建了一个简单的User
类和一个ReifiedUser
继承自它的类。该类User
有companion object
一个 NONE 实例。用实例实例BehaviorSubject
化User.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)
无论我需要在哪里使用activeUser
它flatMap
,Observable.empty()
如果它是 NONE 或者只是弄清楚它是什么以及在订阅者中做什么。
我不喜欢将 javaOptional
与可空的 kotlin 混合,因为混合map
会let
变得非常混乱和丑陋。这样一来,发生的事情就很明显了。
我认为编写一个容器类(例如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))
}
}
}