Trying to do some basic RxJava stuff to lear how it works and was trying to show a progress on button click in a login form (with the RxBindings lib) and then make it disappear after a second. But after the progress is shown and I want to hide it the app crashes. Here's the code I trying to do this with,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
RxView.clicks(findViewById(R.id.email_sign_in_button))
.doOnNext(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
showProgress(true);
}
})
.observeOn(AndroidSchedulers.mainThread())
.delay(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
showProgress(false);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
Toast.makeText(LoginActivity.this, "Threw: " + throwable, Toast.LENGTH_LONG).show();
}
});
}
private void showProgress(final boolean show) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
}
and the crash I get is,
ComposedException 1 : android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6357) at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:909) at android.view.ViewGroup.invalidateChild(ViewGroup.java:4690) at android.view.View.invalidateInternal(View.java:11801) at android.view.View.invalidate(View.java:11765) at android.view.View.setFlags(View.java:9704) at android.view.View.setVisibility(View.java:6693) at android.widget.FrameLayout.setVisibility(FrameLayout.java:208) at com.sample.android.rxlogin.ui.LoginActivity.showProgress(LoginActivity.java:60) at com.sample.android.rxlogin.ui.LoginActivity.access$000(LoginActivity.java:19) at com.sample.android.rxlogin.ui.LoginActivity$1.accept(LoginActivity.java:44) at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:59) 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: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:818) Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.(Handler.java:200) at android.os.Handler.(Handler.java:114) at android.widget.Toast$TN.(Toast.java:344) at android.widget.Toast.(Toast.java:100) at android.widget.Toast.makeText(Toast.java:258) at com.sample.android.rxlogin.ui.LoginActivity$2.accept(LoginActivity.java:49) at com.sample.android.rxlogin.ui.LoginActivity$2.accept(LoginActivity.java:46) at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:72) at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:62) 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.Schedul
I can't understand why this should crash though, since I am using observeOn()
with the main Android thread. Could someone please explain what's wrong here? and whats the right way to do this?