I have an application which is using google maps and listening on camera change. My problem is that on each camera change I have to request my backend. What I want to do is just limiting the number of requests by using RxAndroid/Java to debounce.
My code looks like this:
Observable.create(new Observable.OnSubscribe<CameraPosition>() {
@Override
public void call(Subscriber<? super CameraPosition> subscriber) {
if (!subscriber.isUnsubscribed()) {
map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition cameraPosition) {
subscriber.onNext(cameraPosition);
}
});
}
}
}).subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(Observable.<CameraPosition>empty())
.debounce(1, TimeUnit.SECONDS)
.subscribe(cameraPosition -> {
final LatLngBounds item = map.getProjection().getVisibleRegion().latLngBounds;
homeActionBarActivity.getNMB().getRide().list(
item.southwest.latitude,
item.southwest.longitude,
item.northeast.latitude,
item.northeast.longitude)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(Observable.<List<Ride>>empty())
.subscribe(new Action1<List<Ride>>() {
@Override
public void call(List<Ride> rides) {
clearRidePointsFromMap();
for (Ride ride : rides) {
if (isAdded())
addRideStartPointToMap(ride);
}
}
});
});
As you can see, I am forcing to use the MainThread for both (subscribeOn and observeOn) but I still get this error "Not on the main thread".
Here the stacktrace:
01-27 10:59:24.049 3049-3066/com.nousmotards.android E/AndroidRuntime﹕ FATAL EXCEPTION: RxComputationThreadPool-2
Process: com.nousmotards.android, PID: 3049
java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:52)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:864)
Caused by: rx.exceptions.OnErrorNotImplementedException: Not on the main thread
at rx.Observable$31.onError(Observable.java:7134)
at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:154)
at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)
at rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:137)
at rx.observers.SerializedObserver.onNext(SerializedObserver.java:159)
at rx.observers.SerializedSubscriber.onNext(SerializedSubscriber.java:81)
at rx.internal.operators.OperatorDebounceWithTime$DebounceState.emit(OperatorDebounceWithTime.java:128)
at rx.internal.operators.OperatorDebounceWithTime$1$1.call(OperatorDebounceWithTime.java:72)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:864)
Caused by: java.lang.IllegalStateException: Not on the main thread
at com.google.k.a.cl.b(Unknown Source)
at com.google.maps.api.android.lib6.c.ca.a(Unknown Source)
at com.google.maps.api.android.lib6.c.el.l(Unknown Source)
at com.google.android.gms.maps.internal.l.onTransact(SourceFile:312)
at android.os.Binder.transact(Binder.java:361)
at com.google.android.gms.maps.internal.IGoogleMapDelegate$a$a.getProjection(Unknown Source)
at com.google.android.gms.maps.GoogleMap.getProjection(Unknown Source)
at com.nousmotards.android.fragments.home.MapFragment.lambda$onViewCreated$33(MapFragment.java:117)
at com.nousmotards.android.fragments.home.MapFragment.access$lambda$0(MapFragment.java)
at com.nousmotards.android.fragments.home.MapFragment$$Lambda$1.call(Unknown Source)
at rx.Observable$31.onNext(Observable.java:7139)
at rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:130)
at rx.observers.SerializedObserver.onNext(SerializedObserver.java:159)
at rx.observers.SerializedSubscriber.onNext(SerializedSubscriber.java:81)
at rx.internal.operators.OperatorDebounceWithTime$DebounceState.emit(OperatorDebounceWithTime.java:128)
at rx.internal.operators.OperatorDebounceWithTime$1$1.call(OperatorDebounceWithTime.java:72)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:864)
Do you have any idea ?
Note: if I get out map.setOnCameraChangeListerner(...) from Observable.create(...) it works correctly.
Ok it seems that is (probably) due to the RxJava internal on how it is managed to pass objects from subscriber to observers. I fix my problem by simply getting LatLngBounds inside the subscriber and not the observer.
Observable.create(new Observable.OnSubscribe<LatLngBounds>() {
@Override
public void call(Subscriber<? super LatLngBounds> subscriber) {
if (!subscriber.isUnsubscribed()) {
map.setOnCameraChangeListener(cameraPosition ->
subscriber.onNext(map.getProjection().getVisibleRegion().latLngBounds));
}
}
}).subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(Observable.<LatLngBounds>empty())
.debounce(1, TimeUnit.SECONDS)
.subscribe(item -> {
homeActionBarActivity.getNMB().getRide().list(
item.southwest.latitude,
item.southwest.longitude,
item.northeast.latitude,
item.northeast.longitude)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(Observable.<List<Ride>>empty())
.subscribe(new Action1<List<Ride>>() {
@Override
public void call(List<Ride> rides) {
clearRidePointsFromMap();
for (Ride ride : rides) {
if (isAdded())
addRideStartPointToMap(ride);
}
}
});
});
Hope this will help :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With