-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add RxJava support #1710
Add RxJava support #1710
Conversation
@@ -81,7 +82,7 @@ | |||
*/ | |||
|
|||
@RealmClass | |||
public abstract class RealmObject { | |||
public abstract class RealmObject<E extends RealmObject> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch :( That's not pretty...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it is horrible. Fortunately it is only required for RealmObjects as both RealmResults and RealmList has the type information.
I tried different versions of generics black magic, but AFAIK it isn't possible for an abstract class to return a subclass type without it being explicitly defined somewhere (either as a generic like here, or as input parameter to a method)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It kind of makes me reconsider RealmObservable.from()
and allow users to throw anything at it, a bit like http://reactivex.io/RxJava/javadoc/rx/Observable.html#from(java.util.concurrent.Future)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the pattern is not unknown from RxJava itself: Observable.from()
, Observable.just()
, but it really really break up the flow when you are coding. I tried it when working on the examples.
Upside is that you don't actually need the generic, but if you don't add it you just get Object as the return type in the Observable chain.
I have been contemplating if we should add an explicit ListenerInterface, but that just seems like unnecessary boilerplate
final RealmChangeListener listener = new RealmChangeListener() { | ||
@Override | ||
public void onChange() { | ||
subscriber.onNext(realm); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this should be checking subscriber.isUnsubscribed()
before calling onNext
to follow the Rx contract. Same with all the other from
methods.
More info:
http://ryanharter.com/blog/2015/07/07/wrapping-existing-libraries-with-rxjava/
https://www.reddit.com/r/androiddev/comments/3vebo3/resubmission_respect_the_observable_contract_when/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @austynmahoney
Thanks for the pointers. However I added the subscriber.add(...)
below to prevent that exact scenario. That should unregister the listener when unsubscribing which means it shouldn't be needed to check for subscriber.isUnsubscribed
in the callback. I won't rule out I made a mistake somewhere though, so i'll go over it again :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still vote for following the contract and adding the check anyways. If some code changes down the road, or the unsubscribe happens on another scheduler, it could end up breaking the contract.
Ready for review @realm/java |
@@ -0,0 +1,288 @@ | |||
package io.realm; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Standard header?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
I see no tests for |
We don't have to write any tests for them yet, as the API is not exposed, so there is nothing that can crash. I added i.e. without the methods |
* Creates an Observable for a {@link Realm}. It should emit the initial state of the Realm when subscribed to and | ||
* on each subsequent update of the Realm. | ||
* | ||
* Realm observables are hot observables as Realms automatically are kept up to date. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Realm observables are hot observables as Realms automatically are kept up to date.
as Realms are automatically kept up to date.
same for the below repetitions
Issues fixed @realm/java |
👍 (you have responded to my comments) |
realm.where(AllTypes.class).findFirstAsync().<AllTypes>asObservable().subscribe(new Action1<AllTypes>() { | ||
@Override | ||
public void call(AllTypes rxObject) { | ||
subscriberCalled.addAndGet(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be subscriberCalled.incrementAndGet()
👍 apart from very minor comments |
c54bca1
to
d6db860
Compare
|
||
// Immediately call onNext with the current value, as due to Realms auto-update, it will be the latest | ||
// value. | ||
subscriber.onNext(results); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also check subscriber.isUnsubscribed()
here as well or drop the if
on line 128 depending on how eagerly you want to handle the small removeChangeListener/unsubscription window.
This PR fixes #865
This PR is a feature branch for collecting all RxJava sub-branches before merging. Right now the roadmap is this:
DetachedCopyObservableFactory
class for making all RealmData in-memory data. We need to expose handover for RealmObject/RealmResults. -> Probably not possible to do transparently before Thread handoff for RealmObject and RealmResults / Frozen state #1208 at which it most likely becomes moot anyway.1 + 2 is required before merging to main branch, 3 would be nice to have, 4 + 5 will probably take a little longer and will tie into handover mechanisms already considered elsewhere.
API: (for step 1)
Note that all Rx classes are in a new package
io.realm.rx
. Should we move these intoio.realm
as that currently holds all our public API? It doesn't conflict with the proposal of addingio.realm.android
(as RxJava is not Android only), but something to consider when adding future classes/functionality.io.realm.rx
without making BaseRealm public, is having them inio.realm
OK? Otherwise should we make BaseRealm public but perhaps exclude it from JavaDoc? Answer: Added methods explicitly naming Realm/DynamicRealm to work around this.RealmObject<E extends RealmObject<E>>
which is slightly painful if you want type safe observables for RealmObjects. You need to dopublic class Person extends RealmObject<Person>
. It is not mandatory though. Answer: YES, IntelliJ will give you warning if no generic parameter is given, but otherwise it works fine in all other cases, i.e. only RxJava users will notice it.copyFromRealm
forInMemoryObservableFactory
( Adds Realm.copyFromRealm() #1849 )observable()
and RxJava is not on the classpath