What is the right way in RxJava to Subscribe to an observable that continuously receives events from different sources at unknown times.
For example: Say we have tasks that are received from a server and the calls to the server could be started from a number of different areas (eg triggered by a push notification, a polling event, user interaction etc).
The only thing we care on the UI is that we are notified of the tasks that have been received. We don't care where they come from. I effectively want to start observing for the life of the Activity and the model updates the observer as required
I have implemented the below class that does what I want, but I'm not sure if it the right way or if RxJava already accounts for something like this.
This class effective creates on ConnectableObservable that can have many observers subscribe to the one Observable(ensure all observers get the same stream). One thing I have noticed is calling observeOn and subscribeOn can cause unexpected results when subscribing to a ConnectableObservable in this fashion which can be a problem as the class can't control who is using the ConnectableObservable.
public class ApiService {
private Emitter<String> myEmitter;
private ConnectableObservable myObservable;
public ApiService() {
//Create an observable that is simply used to get the emitter.
myObservable = Observable.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
myEmitter = e;
}
}).publish();
//connect must be called here to ensure we have an instance of the emitter
// before we have any subscribers
myObservable.connect();
}
/**
* This method returns the observable that all observers will subscribe to
*
* #return
*/
public Observable<String> getObservable() {
return myObservable;
}
/**
* This method is used to simulate a value that has been received from
* an unknown source
*
* #param value
*/
public void run(final String value) {
Observable.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
myEmitter.onNext(value);
//api call
}
}).subscribe();
}
}
I'm also curious if there are any concerns with memory leaks doing it this way assuming each observer subscribing to the one Observer is disposed of at the appropriate time.
This is the refactored class after seeing Bob's answer
public class ApiService {
private PublishProcessor<String> myProcessor = PublishProcessor.create();
public void subscribe(Subscriber<String> subscriber) {
myProcessor.subscribe(subscriber);
}
/**
* This method is used to simulate a value that has been received from
* an unknown source
*
* #param value
*/
public void run(final String value) {
myProcessor.onNext(value);
}
}
Use a Subject (RxJava) or Processor (RxJava 2) to do the subscription. You would then subscribe the subject to each source observable. Eventually, you would subscribe to the subject and get the combined stream of emissions.
Alternatively, you could use a Relay to isolate the downstream observers from any onComplete() or onError() that might come from upstream. This is a better choice when any of the observables might complete before the others.
Related
I have a MVVM architecture in my Android app. In an activity, I invoke a method to try to create something from service/repository and return it. I am using RxJava.
Here is the flow:
I click something in view, it invokes method in the Activity.
Method in Activity invokes method in ViewModel.
Method in ViewModel invokes method in Interactor(/use-case).
Interactor has access to service and tries to create something from that service.
Here is the code for this:
Activity:
#Override
public void onCreateWalletClick(String password) {
addWalletViewModel.createWallet(password);
}
ViewModel:
public class AddWalletViewModel extends BaseViewModel {
private AddWalletInteractor addWalletInteractor;
private final MutableLiveData<Wallet> newWallet = new MutableLiveData<Wallet>();
private final MutableLiveData<ErrorCarrier> newWalletError = new MutableLiveData<ErrorCarrier>();
public LiveData<Wallet> newWallet() {
return newWallet;
}
public AddWalletViewModel(AddWalletInteractor addWalletInteractor) {
this.addWalletInteractor = addWalletInteractor;
}
public Single<Wallet> createWallet(String password){
return addWalletInteractor.addWallet(password)
.subscribe(wallet -> newWallet.postValue(wallet), this::addErrorToLiveData);
}
private void addErrorToLiveData(Throwable throwable){
newWalletError.postValue(new ErrorCarrier());
}
}
Interactor:
public class AddWalletInteractor {
private final KeyStoreServiceInterface keyStoreServiceInterface;
public AddWalletInteractor(KeyStoreServiceInterface keyStoreServiceInterface) {
this.keyStoreServiceInterface = keyStoreServiceInterface;
}
public Single<Wallet> addWallet(String password){
return keyStoreServiceInterface.
createWalletAndReturnWallet(password);
}
}
Service:
#Override
public Single<Wallet[]> getAllWallets() {
return Single.fromCallable(()-> {
Accounts accounts = keyStore.getAccounts();
int amount = (int) accounts.size();
Wallet[] wallets = new Wallet[amount];
for (int i = 0; i<amount; i++){
org.ethereum.geth.Account gethAccount = accounts.get(i);
wallets[i] = new Wallet(gethAccount.getAddress().getHex().toLowerCase());
}
return wallets;
}).subscribeOn(Schedulers.io());
}
Problem is I can not manage to get this to work by tweaking the code. Right now it forces me to cast to (Single) in the return of the createWallet() method in the viewmodel. When running the app, it crashes in that method with:
java.lang.ClassCastException:
io.reactivex.internal.observers.ConsumerSingleObserver cannot be cast
to io.reactivex.Single
at addwallet.AddWalletViewModel.createWallet(AddWalletViewModel.java:31)
Please keep in mind I am new to RxJava, I am still trying to figure it out. Any suggestions here?
The cast performed in the createWallet method will always fail.
Solution 1
The simplest way to fix the crash is to change the return type of that method to io.reactivex.disposables.Disposable, assuming you're using RxJava 2. If you're using RxJava 1, then have it return rx.Subscription. The code you presented that calls the createWallet method doesn't seem to use the returned value so it shouldn't make a difference.
Solution 2
If you really do need the return type to be Single and you want to keep the same behavior, then an alternate solution would be to change the createWallet method as follows:
public Single<Wallet> createWallet(String password) {
return addWalletInteractor.addWallet(password)
.doOnSuccess(wallet -> newWallet.postValue(wallet))
.doOnError(this::addErrorToLiveData);
}
The method now returns a new Single that does whatever the Single returned from addWallet does and additionally invokes the appropriate lambda function when a value is successfully emitted or an error occurs. You would also need to modify the call site for the method as follows:
#Override
public void onCreateWalletClick(String password) {
addWalletViewModel.createWallet(password).subscribe();
}
That subscribe call is needed to have the Single start emitting values. It takes no parameters because you already do all of the interesting work in the createWallet method itself. Both snippets were written with RxJava 2 in mind, but I believe they will also work in RxJava 1 as is.
If you haven't already done so, you should check out the official Rx website as it provides a ton of information on how reactive streams work and how to use them.
Since you're new to RxJava and the documentation is so vast, here's a brief overview of the subscription concept and how it applies to your situation.
RxJava and other stream-based libraries like it have two main components: producers and consumers. Producers supply values and consumers do something with those supplied values.
Single is a kind of producer that only produces one value before terminating. In your case, it produces a reference to the newly created wallet. In order to do something with that reference, it needs to be consumed. That's what the subscribe method on the Single class does. When the Single returned by the addWallet method produces a value, the lambda passed to the subscribe method is invoked and the wallet parameter in that lambda is set to the produced value.
The return type of the subscribe method is NOT itself a Single. When a consumer and a producer are coupled together by the subscribe method, it forms a connection which is represented by the Disposable class. An instance of that class has methods to cancel the connection before the producer is done producing values or to check if the connection has been cancelled. It is this connection object that is returned by the subscribe method.
Note that until this connection is made via one of the subscribe overloads, the producer will not start producing items. I.e., a Single that is never subscribed to will never do anything. It's analogous to a Runnable whose run method is never called.
I'm currently trying to move an application over to RxJava 2 to replace our broadcast receiver methods of passing events around. The goal here was to used Rx with a pubSub pattern in mind.
(Just a heads up, the following class which acts as an event bus was taken from an article I found online and I do believe I don't understand the working to 100% which I is probably why I can't find the fix of the problem).
My problem: I have a library that gives emits certain events (in this case a Bluetooth library that handles connection, pairing, data processing, etc...). The activities interested in these events can subscribe to certain or all of them to get notified when the library has something. I guess it is important to say that I AM getting responses from my library (so data), but I cannot change the UI (I can add words to a textview but that's about it) when my activity receives the response. I do understand that the threads that onNext() will run on is where the subscribe was called for, and as of right now, the subscribe on is NOT explicitly called by my activity ( I'll paste in the code below).
Snippet of activity registration to events:
EventBus.subscribe(EventBus.Events.CONNECTED, this, new Consumer<Object>()
{
#Override
public void accept(Object device)
{
if(device instanceof DeviceStructure)
{
if(uuid.equals(((DeviceStructure) device).getUUID()))
{
status_value.append("device connected " + ((DeviceStructure) device).getUUID());
}
else if(name.equals(((DeviceStructure) device).getName()))
{
status_value.append( "device connected " + name + " " + address);
}
}
}
}
);
EventBus.subscribe(EventBus.Events.PAIRED, this, new Consumer<Object>()
{
#Override
public void accept(Object device)
{
if(device instanceof DeviceStructure)
{
if(((DeviceStructure) device).getPairedStatus())
{
uuid = ((DeviceStructure) device).getUUID();
status_value.append("device paired " + uuid);
pair.setEnabled(false);
sync.setEnabled(true);
unpair.setEnabled(true);
}
}
}
});
I am able to modified the status_value values and display some text. However, I am unable to do pair.setEnabled(false) ( The part where the error gets thrown)
The event bus class:
public final class EventBus {
public enum Events
{
CONNECTED,
PAIRED
}
private static Map<Events, PublishSubject<Object>> sSubjectMap = new HashMap<>();
private static Map<Object, CompositeDisposable> sSubscriptionsMap = new HashMap<>();
private EventBus() {
// hidden constructor
}
/**
* Get the subject or create it if it's not already in memory.
*/
#NonNull
private static PublishSubject<Object> getSubject(Events event) {
PublishSubject<Object> subject = sSubjectMap.get(event);
if (subject == null) {
subject = PublishSubject.create();
subject.subscribeOn(AndroidSchedulers.mainThread());
sSubjectMap.put(event, subject);
}
return subject;
}
/**
* Get the CompositeDisposable or create it if it's not already in memory.
*/
#NonNull
private static CompositeDisposable getCompositeDisposable(#NonNull Object subscriber) {
CompositeDisposable compositeDisposable = sSubscriptionsMap.get(subscriber);
if (compositeDisposable == null) {
compositeDisposable = new CompositeDisposable();
sSubscriptionsMap.put(subscriber, compositeDisposable);
}
return compositeDisposable;
}
/**
* Subscribe to the specified subject and listen for updates on that subject. Pass in an object to associate
* your registration with, so that you can unsubscribe later.
* <br/><br/>
*/
public static void subscribe(Events subject, #NonNull Object subscriber, #NonNull Consumer<Object> action) {
Disposable disposable = getSubject(subject).subscribe(action);
getCompositeDisposable(subscriber).add(disposable);
}
/**
* Unregisters this object from the bus, removing all subscriptions.
* This should be called when the object is going to go out of memory.
*/
public static void unregister(#NonNull Object lifecycle) {
//We have to remove the composition from the map, because once you dispose it can't be used anymore
CompositeDisposable compositeDisposable = sSubscriptionsMap.remove(lifecycle);
if (compositeDisposable != null) {
compositeDisposable.dispose();
}
}
/**
* Publish an object to the specified subject for all subscribers of that subject.
*/
public static void publish(Events subject, #NonNull Object message) {
getSubject(subject).onNext(message);
}
}
I have tried the following solutions proposed online to indicate that I would like the subscriber to run on the main thread ( which should be the UI thread, unless I got that wrong).
subject.observeOn(AndroidSchedulers.mainThread());
subject.delay(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread());
subject.subscribeOn(AndroidSchedulers.mainThread());
subject.subscribeOn(AndroidSchedulers.from(Looper.getMainLooper()));
I have also found this link : https://github.com/ReactiveX/RxAndroid/issues/371 but the solution provided still doesn't seem to like what my activity is doing.
I guess it is also worth noting that when I enter the accept method in PAIRED action, the thread isn't the UI thread at that point.
Edit:
I'll leave this on just for other people like me. I had to add the observeOn to my disposable object and not in my getSubject() method which is where I added it from.
if (subject == null) {
subject = PublishSubject.create();
subject.subscribeOn(AndroidSchedulers.mainThread());
The result of subscribeOn is ignored.
Technically what you must do is somehow interject an observeOn(AndroidSchedulers.mainThread()) before you receive your event from the relay to the subscriber.
A possibility is to define an Observable.Transformer that you can compose which will apply the observeOn.
#SuppressWarnings("unchecked")
<T> Observable.Transformer<T, T> observeOnMain() {
return tObservable -> tObservable.observeOn(AndroidSchedulers.mainThread());
}
and
.compose(observeOnMain())
.subscribe(subscriber);
New to RxJava and I have question about interface callbacks ( called from inner layer/module of code through interface variable) vs RxJava.
To make it more clear, quick example:
Standard callback interface implementation, interface, class A and B
interface CustomCallback {
void onCallbackCalled(String str);
}
class ClassA {
private ClassB classB;
public ClassA() {
classB = new ClassB(new CustomCallback() {
#Override
public void onCallbackCalled(String str) {
System.out.println("Callback called " + str);
}
});
}
}
class ClassB {
private CustomCallback customCallback;
public ClassB(CustomCallback callback) {
customCallback = callback;
}
private void somethingHappened() {
customCallback.onCallbackCalled("method somethingHappened");
}
}
When classB method "somethingHappened" is called, result is: "Callback called method somethingHappened".
Interface's method onCallbackCalled(String str) can be called from classB as many times as I want.
CLASS A ↓ ............................................ injection of interface through constructor
CLASS B................↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ onCallbackCalled(...) 0...n number
Now RxJava. 99% of cases which I find.
class ClassA {
private ClassB classB;
public ClassA() {
classB = new ClassB();
}
public void rxJavaMethod() {
DisposableObserver<String> observer = classB.getObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<String>() {
#Override
public void onNext(String s) {}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {}
});
}
}
class ClassB {
private Observable<String> getObservable() {
return Observable.just(can be different from "just", for sake of example);
}
}
Scheme is:
CLASS A ↓........................ one call for getting Observable resource
CLASS B................↑ EDIT returns observable which emits 0...n values
So basically you call from top layer ( in this example) and you get response about state from inner layer.
QUESTIONS:
1) What in case when you have a model ( inner layer) which is changing dynamically ( but not any kind of AsyncTask etc.), and you want to notify top layer ( UI for example) that state has changed ( good example: game).
2) Is there any kind of "bridge" class in RxJava library ( I think about it as "subscribe to it, then you can pass arguments to it as many times as you want and information/observable will be emitted to subscribers).
3) Is there any sense and advanatage of trying to do that instead of standard interface callbacks ( in case like above, not " click button, get response once")
UPDATE, ANSWER BASED ON EXAMPLE ABOVE
As Bob Dalgleish mentioned, way of making such bridge is by using one of the class extending Subject<T> rxjava.
http://reactivex.io/documentation/subject.html
class ClassA {
private ClassB classB;
public ClassA() {
classB = new ClassB();
}
public void rxJavaMethod() {
DisposableObserver<String> observer = classB.getCallbackSubjectRx()
.subscribeWith(new DisposableObserver<String>() {
#Override
public void onNext(String s) {}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {}
});
}
}
class ClassB {
private BehaviorSubject<String> mCallbackRx;
public ClassB() {
mCallbackRx = BehaviorSubject.create();
}
// method somethingHappened can be invoked whenever whe want and
// it will send given parameter to all subscribers
private void somethingHappened() {
mCallbackRx.onNext("method somethingHappened");
}
// multiple subscribers allowed
public BehaviorSubject<String> getCallbackSubjectRx() {
return mCallbackRx;
}
}
Downside might be, that if we want to use one "bridge" to handle multiple callback types ( interface have methods, we use only one method: "onNext()"), we might need to create wrapper class with callback parameters. Which isn't big problem in my opinion.
On the other hand, we get access to all of RxJava operators.
http://reactivex.io/documentation/operators.html
( Example above is for RxJava2, where Disposable is basically Subscription from RxJava1).
The first thing to note is that
CLASS B................↑ returns 0...n observables to observer
is not true. Class B returns an observable, on which it will occasionally emit 0..n values.
(the question is not clear). The inner observable, from class B, is changing state for whatever reason. The most common reason is that another process/task/thread is feeding it, and you want to display the resulting state in the UI.
A simple type of "bridging" class that I use all the time any of the several Subject<> classes. You can emit new values to them using .onNext() and the subscribers will get those values.
If callback interfaces were all standardized, then they would have some advantage, but they vary all over the place. You have to remember that you need some particular interface for this thing you are looking at and and a different one for the other thing. While UI events tend to be quite uniform these days, trying to mix UI events and network events and database events will still leave you feeling overwhelmed. Having a much smaller class of interfaces, mostly encapsulated inside of the rxJava generic classes, makes composing functionality much easier.
Edit: Improve example code.
There is a good article from Yammer Engineering on using Observable.create() (formerly Observable.fromEmitter(), formerly Observable.fromAsync(). The important points he makes are
Using Observable.create() handles the subscription step for you by registering a listener to the underlying interface. More importantly, it arranges to de-register the listener when the unsubscribe() occurs.
Out of the box, this code handles multiple subscribers, each of which receives its own observable stream of data.
As I mentioned above, the listener protocol is particular to the thing you register with. If that thing supports only a single listener, then you will likely want to introduce a Subject that subscribes to the thing under observation, and all your other observers subscribe to the subject.
End of edit.
My favorite example of composition of solutions is the distinctUntilChanged() operator. Because it is an operator that works on a generic observable, it encapsulates the stateful property of saving consecutive values for comparison and only emitting differing ones. I use it frequently for logging state changes. To achieve the same end using standard callback interfaces would require adding a different interface for saving prior values to every existing interface.
So, yes, most of the time it is worth using the rxJava approach of observables, simply for the sake of not having to remember which of the many call back protocols might be applicable in the current case.
I used to work with EventBus before, which was easy to use and easy to understand. This time, however, I would like to try out RxJava for event bus-like communication, however it is not very clear how to remove events from RxJava or, better to say, how it should be designed properly to have similar behavior as EventBus has when I call removeStickyEvent?
In RxJava I can use BehaviorSubject to reply last even when I subscribe to this observable, but what should I do when this event is handled? What if I do not want to have this event replayed again?
For instance, one fragment fires an event and then finishes. Another fragment listens to this event and handles it. Then, if this app fires that "another" activity again from different circumstances, then it will subscribe to the same BehaviorSubject again and will handle that stale event again, which is not what I would like to achieve.
I used this project as a reference https://github.com/marwinxxii/AndroidRxSamples/blob/master/app/src/main/java/com/github/marwinxxii/rxsamples/EventBusSampleActivity.java
As long as you do not plan to allow your events to be null, I think that can be achieved pretty easily.
Exactly as you said, you could use BehaviorSubject to propagate sticky events, and when you want to removeStickyEvent from the bus, you can just emit a null object (to "flush" the subject).
Something like this (from the top of my head - not tested, without generics, just a simple Object-event based example):
public class RxEventBus {
PublishSubject<Object> eventsSubject = PublishSubject.create();
BehaviorSubject<Object> stickyEventsSubject = BehaviorSubject.create();
public RxEventBus() {
}
public Observable<Object> asObservable() {
return eventsSubject;
}
public Observable<Object> asStickyObservable() {
return stickyEventsSubject.filter(new Func1<Object, Boolean>() {
#Override
public Boolean call(Object o) {
return o != null;
}
});
}
public void postEvent(#NonNull Object event) {
eventsSubject.onNext(event);
}
public void postStickyEvent(#NonNull Object stickyEvent) {
stickyEventsSubject.onNext(stickyEvent);
}
public void removeStickyEvent(){
stickyEventsSubject.onNext(null);
}
}
I have a Bound Service which responsible for downloading files and thus it knows the downloading status/progress. And the UI (Fragment or Activity) has to show/update download progress from the service.
Actually i think the common way is to use BroadcastReciever or a CallBack from Activity. But i heard somewhere about using RxJava (ReactiveX Programming) and mediator class (and Dagger to inject it into both service and activity) which is mentioned below.
So my question is how to handle RxJava with these bunch of stuff? Any Code Samples? Is there another efficient way than using intents?
Resource:
More efficient way of updating UI from Service than intents? [ see the first answer update ]
Required of RxJava/RxAndroid
1) OBSERVABLES
2) OBSERVERS
3) SUBSCRIBE
Plan where you need to place your 1, 2, 3,
OBSERVABLES go where the data is created, so In your case SERVICE
OBSERVERS go where the data needs to be consumed(or displayed), so that's your ACTIVITY
SUBSCRIBE goes anywhere where you have access to OBSERVABLE & OBSERVER, so lets use ACVITITY for that
Procedure and Code:
Firstly,
Prepare your OBSERVABLE in service like this
class MyService extends Service {
static PublishSubject<String> data = PublishSubject.create();
#Override
public void onStarCommand(Intent intent,int i, int j){
# DO THIS ANYWHER WHERE YOU GENERATE DATA
data.onNext("Hello");
}
public static Observable<String> getObservable(){
return data;
}
}
Secondly,
Prepare your OBSERVER(and OBSERVABLE) in Activity's onCreate
Observable<String> observable = MyService.getObservable();
Observer<String> observer = new Observer<String>() {
#Override
public void onCompleted() {
Log.d(TAG, "onCompleted: ");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "onError: ",e);
}
#Override
public void onNext(String text) {
Log.d(TAG, "DATA reveived here: "+text);
}
};
Lastly
Link both OBSERVER and OBSERVABLE in Activity, else Observable will not respond,
use this again in onCreate
observable.subscribe(observer);
DONE, Now when even the data is triggered from Service using onNext(), the data arrives in Activity
The Binder subclass you use when something binds to your Service can expose a method that returns an Observable which emits progress data.
The caveat with this approach is that you have two resources which you need to release when the Activity instance is no longer valid: the service connection and the observable subscription.