[英]How to pass null to an Observable with nullable type in RxJava 2 and Kotlin
I initialize my variable like this:-我像这样初始化我的变量:-
val user: BehaviorSubject<User?> user = BehaviorSubject.create()
But I can't do this.但我不能这样做。 IDE throws an error:-
IDE 抛出错误:-
user.onNext(null)
And doing this, IDE says u will never be null:-这样做,IDE 说你永远不会为空:-
user.filter( u -> u!=null)
As Guenhter explained, this is not possible.正如Guenhter解释的那样,这是不可能的。 However, instead of proposing the null-object pattern, I'd recommend an implementation of the
Optional
type:但是,我不建议使用空对象模式,而是建议实现
Optional
类型:
data class Optional<T>(val value: T?)
fun <T> T?.asOptional() = Optional(this)
This makes your intent much clearer, and you can use a destructuring declaration in your functions:这使您的意图更加清晰,您可以在函数中使用解构声明:
Observable.just(Optional("Test"))
.map { (text: String?) -> text?.substring(1)?.asOptional() }
.subscribe()
Using the null-object pattern here can cause more bugs than it solves.在这里使用空对象模式可能会导致比它解决的更多的错误。
If you use rxkotlin/rxjava 2.0 (I assume so) than the answer is: you can't.如果您使用 rxkotlin/rxjava 2.0(我认为是),那么答案是:您不能。 The reason is explained here.
原因在这里解释。
This is a break of the interface.这是界面的中断。 Have a look at the
Observable
Interface查看
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);
...
The @NonNull
will be considered by the Kotlin compiler and therefore you CAN'T pass null. @NonNull
将被 Kotlin 编译器考虑,因此您不能传递 null。
Even if you could, the onNext
would immediately throw an error:即使可以,
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;
}
...
}
If you really need such a thing as null
you have to fake it.如果你真的需要像
null
这样的东西,你必须伪造它。 eg by creating a static object of User
which represents your null
-element.例如,通过创建代表您的
null
元素的User
静态对象。
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 }
But if is somehow possible, try to avoid the null
concept and maybe think of another solution where this isn't needed.但是,如果有可能,请尽量避免使用
null
概念,并且可能会考虑另一种不需要的解决方案。
Thank you very much for all your answers but I ultimately went with this solution:-非常感谢您的所有回答,但我最终采用了这个解决方案:-
class UserEnvelope(val user:User?) {}
And using this in the observables.并在 observables 中使用它。
This best suited my requirements.这最适合我的要求。
I am new to Kotlin so I don't know how to use Optionals.我是 Kotlin 的新手,所以我不知道如何使用 Optionals。 But from what I understand, I would have to typecast it to User type everytime I need to observe the values right?
但据我所知,每次我需要观察值时,我都必须将其类型转换为用户类型,对吗?
To implement the solution mentioned in the nhaarman 's answer, you can use the util class Optional
( doc ) from the Android SDK which was added in API level 24 .要实现nhaarman的答案中提到的解决方案,您可以使用 Android SDK 中的 Util 类
Optional
( doc ),该类在API 级别 24 中添加。
If your app's minSdkVersion
less than 24 then you still need to implement it by yourself.如果您的应用程序的
minSdkVersion
小于 24,那么您仍然需要自己实现它。
Since RxJava 2 does not support null values, there are some other acceptable solutions you can use:由于 RxJava 2 不支持空值,您可以使用其他一些可接受的解决方案:
Any
class instances with your subject type.Any
类实例。 For example you could create an Empty.INSTANCE
enum class which would emulate the null value and then filter by the enum class.Empty.INSTANCE
枚举类,该类将模拟空值,然后按枚举类进行过滤。 The last one is the one I use and prefer being a variant of the previous solution and is based on specialisations.最后一个是我使用的,并且更喜欢作为前一个解决方案的变体并且基于专业化。 Our friends of JetBrains always emphasise that classes are very cheap in Kotlin, so this would be a quick example to distinguish logged users and not logged ones:
我们 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()) }
I've taken an approach similar to Optional<User>
and UserEnvelope
.我采用了类似于
Optional<User>
和UserEnvelope
。 I make a simple User
class and a ReifiedUser
class that inherits from it.我创建了一个简单的
User
类和一个继承自它的ReifiedUser
类。 The User
class has a companion object
that has a NONE instance. User
类有一个带有 NONE 实例的companion object
。 The BehaviorSubject
is instantiated with the User.NONE
instance. BehaviorSubject
是用User.NONE
实例实例化的。 It looks something like this:它看起来像这样:
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()
My BehaviorSubject
is instantiated like this:我的
BehaviorSubject
实例化如下:
val activeUser: BehaviorSubject<User> = BehaviorSubject.createDefault(User.NONE)
And wherever I need to use activeUser
I either flatMap
it to Observable.empty()
if it's NONE or just figure out what it is and what to do in the subscriber.在我需要使用
activeUser
任何地方,如果它是 NONE,我要么将它flatMap
到Observable.empty()
,要么只是弄清楚它是什么以及在订阅者中做什么。
I don't like mixing java Optional
with kotlin nullable because mixing map
and let
gets really confusing and ugly.我不喜欢将 java
Optional
与 kotlin nullable 混合,因为混合map
和let
会变得非常混乱和丑陋。 This way it's very obvious what's going on.这样就很清楚发生了什么。
I think it makes more sense to write a container class such as Result
.我认为编写一个诸如
Result
类的容器类更有意义。 An example of that would be一个例子是
data class Result<T>(value: T?, error: Throwable?)
Usage用法
Observable.create { observer ->
upstreamService.listen(object: UpstreamListener {
onSuccess(data: User) {
observer.onSuccess(Result(data))
}
onError(exception: Throwable) {
observer.onSuccess(Result(null, exception))
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.