I have a function that creates Observable:
void getData() {
Observable.create(emitter -> {
// call webservice
.......
emitter.onNext(myData);
}).subscribe(data -> {
// Process data here
});
}
I don't want to use Disposable here. I think the observable is local variable, so it will be released after the function is done.
Is the observable released automatically after I call getData() function?
Observable will automatically dispose they called onComplete() or onError()
Ex: You have a method to load exactly data from 10 files Observable<String> loadFiles() which return Observable.create(). Then every time you want to emit value you call e.onNext(), after count 10 times you will call e.onComplete() to mark that your Observable has finish it's work, then it will auto dispose.
You only need to call dispose() method to indicate that the Subscriber is no longer interested in any of the Observables it is currently subscribed to. Those Observables can then (if they have no other interested observers) choose to stop generating new items to emit.
Call dispose() when activity stopped to make sure that no more emission will come after that. So it's a good practice because it can prevent memory leaks and waste of resources, network calls.
Observables do not dispose them-selfs.
It's a good practice to dispose your observable to avoid memory leaks and crashes of your app.
you either use disposable.dispose() or compositeSubscribtion.clear().
I have made a simple test and after I exited the app(back btn) observable continued to emit data.
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Observable.create(emitter -> {
for (; ; ) {
emitter.onNext("data");
Thread.sleep(3000);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).
subscribe(data -> {
Log.d(tag, (String) data);
});
}
});
OUTPUT :
onStart() is called
onResume() is called
data
data
onPause() is called
onStop() is called
data
data
Related
I have an async method makeRequest() with callback. It called many times from different classes of my application. I need that this calls start one by one and never simultaneously.
I want to implement this using Rx. Like this:
public void execute() { // This method called many times from another classes
Observable.just(true)
// what I need to add here?
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(o -> {
internalExecute();
return o;
})
.subscribe();
}
private void internalExecute() { // This method should called only when previous call was finished
makeRequest(this::onRequestFinished);
}
private void onRequestFinished() {
// here is I handle request finish
}
But at now all requests works at parallel. What I need to add here to run requests one by one?
According to comments, you have here separated streams and requests. each client that execute request expect a result from the request. but no requests allowed to run in parallel, in this case I think the easiest way is to limit the Scheduler to an application global background sequential thread Executor, i.e:
Schedulers.from(Executors.newSingleThreadExecutor())
provide somewhere in your app this single thread Executor, in singleton manner of course, it's important that each request stream will use the same object:
private final Scheduler singleThreadScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
public void execute() { // This method called many times from another classes
Observable.just(true)
.map(o -> {
internalExecute();
return o;
})
.subscribeOn(singleThreadScheduler)
.subscribe();
}
private void internalExecute() { // This method should called only when previous call was finished
makeRequest(this::onRequestFinished);
}
private void onRequestFinished() {
//NOTE: you should make sure that the callback execute where you need it (main thread?)
// here is I handle request finish
}
besides that, you're not exposing Observable outside, to the clients, but rather using callback mechanism, you can leverage reactive approach further, by making execute() returning Observable. (and enjoy composition of Obesrvables, operators, proper use of observeOn/subscribeOn, error handling with onError, disposing/unsubscribing etc.), as you're using async api, you can use fromEmitter()/create() (in newer RxJava1 version)), read more here:
private final Scheduler singleThreadScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
public Observable<Result> execute() { // This method called many times from another classes
return Observable.fromEmitter(new Action1<Emitter<? extends Object>>() {
#Override
public void call(Emitter<?> emitter) {
emitter.setCancellation(() -> {
//cancel request on unsubscribing
});
makeRequest(result -> {
emitter.onNext(result);
});
}
})
.subscribeOn(singleThreadScheduler)
}
I am using RxJava for listening an event of Bluetooth adapter. The bluetooth listener may be active for long duration like for few hours. My question is how long the emitter is valid and I can send events though it?
My code is:
Class BlutoothObserver{
ObservableEmitter emitter;
BlutoothObserver(){
...
starListeningBluetoothDevice();
}
public Observer getObserver(){
return Observable.create(e -> {
emitter =e;
});
}
public void bluetoothCallback(){
...
emitter.onNext();
...
}
}
It should stay alive as long as you do not call onComplete() on emitter.
You will want to be careful with how you define getObserver() though. Right now you are creating a new Observable every time. So if you called getObserver() twice in a row it would return different Observable instances and only the last one returned would be of use. I would just create a field for the Observable and set it at construction time.
Keeping it simple and short, how to subscribe to an observable in another subscriber's onNext() method so that we can only make nested subscription when the current observable completes its execution. Both the subscriptions will be made on separate threads and the requirement is that the first thread must complete its execution before the second thread is started.
makeObservable()
.subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<User> {
#override
void onNext(User user){
//do something
//make another subscription here
});
Don't make a new subscription, return another Observable and subscribe to it.
apiCall()
.subscribeOn(<scheduler>)
.observeOn(<scheduler>)
.flatMap(new Func1<User, Observable<Something>() {
#Override
public Observable<Something> call(User user) {
return Observable.just(<example>);
}
});
edit: when the api call returns, flatMap will intercept the stream, and from there, either return an Observable or call a function that returns an Observable (ie another api call).
If they're both emitting the same items, use Observable.concat(), which subscribes to observable N+1 after observable N completes. But it might be worth it to describe your use case in more detail.
Edit: You should be able to do something like:
userClient
.saveUser(user)
.flatMap(userSaveResult ->
userClient
.saveUserDetails(userSaveResult.id, seuser.getDetails))
.onError(...)
I have some confusion on subscribers and when they react to observers. Lets say i have the following simple observer with a subscriber that does an action:
Observable.just(preferences.getBoolean(C"vibrate", false))
.subscribeOn(Schedulers.io())//observe on new thread
.observeOn(AndroidSchedulers.mainThread()) //subscribe(listen) on main thread
.subscribe(new Action1<Boolean>() {
#Override
public void call(Boolean shouldVibrate) {
if (shouldVibrate)
Toast.makeText(context,"i should vibrate now",Toast.SHORT).show();
}
});
I realize the observer gets called right away when this code is first seen. But what if the shared preference is changed again afterwards, will this code run again automatically or does it only run everytime i call subscribe ? What if i wanted it to run everytime the shared preference was altered (sort of like a watcher).
It really depends on the observable. I would suggest reading "Hot" and "Cold" Observables on the reactive Observable docs.
In your case, this is a Cold observable. It will resubscribe each time it is subscribed to. However, you only subscribe to it once. Your code snippet will actually block on the preferences fetch (probably not a huge problem), but it will only emit one preference.
I would suggest using the ContentObservable class in the RxAndroid extension lib for RxJava, which you are already using (because of AndroidSchedulers).
It would look something like this (This is back-of-napkin code, I have not compiled or ran this):
// Defer the observable so it gets a fresh preference value. Also, we'll
// be using it a few times.
final Observable<Boolean> vibratePreference = Observable.defer(
new Func0<Observable<Boolean>>() {
#Override
public Observable<Boolean> call() {
return Observable.just(preferences.getBoolean("vibrate", false));
}
});
vibratePreference
.concatWith(ContentObservable.fromSharedPreferencesChanges(preferences)
// Only consider changes to the vibrate preference.
.filter(new Func1<String, Boolean>() {
#Override
public Boolean call(final String key) {
return "vibrate".equals(key);
}
})
// Each time the preference changes, get the latest value.
.flatMap(new Func1<String, Observable<Boolean>>() {
#Override
public Observable<Boolean>(final String unusedKey) {
return vibratePreference;
}
}))
.scheduleOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( /* ...and so on. */ );
Also, if you are doing this on an activity or a fragment, I would strongly suggest looking into bindActivity and bindFragment in AppObservable in RxAndroid to make sure you are binding this observable to the lifecycle. You also may want to store a CompositeSubscription that you can empty in onPause and restore subscriptions in onResume. Those are slightly off-topic but will most likely be useful very soon.
In Why is my timer Observable never called?
#Miguel Lavigne says:
"Keep in mind that if you're using Observables from within a Fragment or an Activity you should always make sure you unsubscribe from your Observables to eliminate chances of memory leaks."
It is clear to me how it works as long as I am using an Observable in an Activity, Fragment or View. But what if I am using it where there is no context?
My situation: I am having an external library which holds an object model. Each object has a .save() function, which is called from the UI. In save, an API endpoint call is performed by an Observable asynchronously.
Example:
public Overlay save() {
Observable.create(new Observable.OnSubscribe<Overlay>() {
#Override public void call(Subscriber<? super Overlay> subscriber) {
try {
Overlay overlay= OverlayEndpoint.insertOverlay(this); // call the API endpoint here
subscriber.onNext(overlay);
subscriber.onCompleted();
} catch (IOException e) {
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Overlay>() {
#Override public void call(Overlay overlay) {
// process the saved result [omitted for brevity]
}
}, new Action1<Throwable>() {
#Override public void call(Throwable throwable) {
// put the overlay into a local upload queue in case the endpoint is unreachable [omitted]
}
});
return this; // return the call immediately
}
The Observable is for one-time use within save and becomes obsolete thereafter. How can I make sure it does not persist?
Situation 1: Normal unsubscribe. Is there a way to unsubscribe right from within the call(), once processing is complete?
Situation 2: For whatever reason the Observable stays in memory. Could I use .timeout() to ensure the Observable is destroyed after enough time has passed?
Situation 1: Normal unsubscribe. Is there a way to unsubscribe right from within the call(), once processing is complete?
In your case, Observable will be in memory before Action1<Overlay> or new Action1<Throwable> is called. But after one of them is called, GC should be able to clean the Observable.
Situation 2: For whatever reason the Observable stays in memory. Could I use .timeout() to ensure the Observable is destroyed after enough time has passed?
In your case, Schedulers.newThread() will create a new Thread to run the Observable.OnSubscribe<Overlay>.call. So if this method has not returned yet, such as OverlayEndpoint.insertOverlay will run about 10 minutes, Observable can not be cleaned by GC because this thread is still using it. There is nothing we can do unless there is an approach to cancel OverlayEndpoint.insertOverlay.