Reputation: 417
Currently trying to mock an api call with RxJava 2 (2.0.6) with delay. It throws a CalledFromWrongThreadException in my view layer (Activity).
Here is my Observable in my presenter
view.refreshLoadStart();
Observable.just(createTicketArray(10))
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.delay(5, TimeUnit.SECONDS)
.subscribe(new Observer<ArrayList<Ticket>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ArrayList<Ticket> tickets) {
if (getView() != null){
view.showTickets(tickets);
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (getView() != null){
view.refreshLoadComplete();
}
}
@Override
public void onComplete() {
if (getView() != null){
view.refreshLoadComplete();
}
}
});
Here is my view methods in my activity
@Override
public void showTickets(final ArrayList<Ticket> tickets) {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
if (recyclerView.getAdapter() == null){
adapter = new TicketAdapter(tickets);
recyclerView.setAdapter(adapter);
} else {
adapter.setTickets(tickets);
adapter.notifyDataSetChanged();
}
recyclerView.setHasFixedSize(true);
// }
// });
}
@Override
public void refreshLoadComplete() {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
swipeRefreshLayout.setRefreshing(false);
Toast.makeText(TicketActivity.this, "Completed", Toast.LENGTH_SHORT).show();
// }
// });
}
@Override
public void refreshLoadStart() {
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
swipeRefreshLayout.setRefreshing(true);
// }
// });
}
Here is the stacktrace of the exception:
Process: com.timmccarthy.litt, PID: 22060
io.reactivex.exceptions.UndeliverableException: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:366)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:62)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:154)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8128)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1220)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.view.View.requestLayout(View.java:20085)
at android.support.v7.widget.RecyclerView.requestLayout(RecyclerView.java:3576)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:4620)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:10448)
at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:6105)
at com.timmccarthy.litt.ui.ticket.TicketActivity.showTickets(TicketActivity.java:82)
at com.timmccarthy.litt.ui.ticket.TicketPresenter$1.onNext(TicketPresenter.java:46)
at com.timmccarthy.litt.ui.ticket.TicketPresenter$1.onNext(TicketPresenter.java:37)
at io.reactivex.observers.SerializedObserver.onNext(SerializedObserver.java:111)
at io.reactivex.internal.operators.observable.ObservableDelay$DelayObserver$1.run(ObservableDelay.java:84)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:154)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Basically I am asking why is this Exception being thrown since on the Observable I am observing on the main thread and not on another thread?
p.s I did find a fix which is the commented out sections in my code, I just see this as a quick fix and it doesn't really address why I am getting the Exception.
Upvotes: 0
Views: 1575
Reputation: 417
Figured out where I went wrong.
My 'swipetorefresh' listener was calling a refresh method on my presenter which had a separate observable.
Removed this second observable, all the problems went away.
Upvotes: 0
Reputation: 3863
It is rather simply actually ,you are modifying views not in the main thread. try this subscribeOn(Schedulers.newThread())
.
does this line gets executed? Toast.makeText(TicketActivity.this, "Completed", Toast.LENGTH_SHORT).show();
the commented out sections wont work because you already on the main thread.
Upvotes: 1