问题
I have the following code, where I start a ring dialog before I make a long running task, done in RxJava2. The problem is that the dialog isn't showing up and I don't think I'm blocking the main UI thread.
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (ringProgressDialog != null) {
if (ringProgressDialog.isShowing()) {
ringProgressDialog.dismiss();
}
}
ringProgressDialog = ProgressDialog.show(SendConversationsActivity.this,
getResources().getString(R.string.creating_document_progress_dialog_title),
getResources().getString(R.string.conversation_progress_dialog_text),
true, false);
FileNameAndContacts filenameAndContacts = new FileNameAndContacts();
if (tvNoDatSelected.getVisibility() != View.VISIBLE) {
filenameAndContacts.setFileName("");
}
createDocument(filenameAndContacts)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Timber.e(throwable, "Error in getting document"))
.subscribe(fileAndContacts -> {
if (ringProgressDialog.isShowing()) { //debugger says
//dialog is showing.
ringProgressDialog.dismiss();
}
sendDocumentInEmail(fileAndContacts);
});
}
Task executes properly. I also show another ring progress dialog before I do another RXJava task in the same activity, this one shows up.
If I comment out the RxJava call, the dialog shows up. So something in the RxJava call is blocking.
//EDIT This simple observable also blocks the progress dialog from showing (but the Toast displays):
Observable.just("Hello, world")
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(disposable -> {
Toast.makeText(SendConversationsActivity.this, "Toast...", Toast.LENGTH_SHORT).show();
//ringProgressDialog.show();
})
.doOnTerminate(() -> {
//ringProgressDialog.dismiss();
})
.subscribe(s -> {
//Toast.makeText(SendConversationsActivity.this, s, Toast.LENGTH_SHORT).show();
ringProgressDialog.dismiss();
});
回答1:
How is createDocument implemented? create, fromCallable
@akarnokd I do the calculations then do a Single.just(fileNameAndContacts)
As suspected, you compute the document on the current thread (main) and blocking it. You should move it into fromCallable
and it will compute in the background when combined with subscribeOn(Schedulers.io())
:
Observable.fromCallable(() -> {
/* compute the document here */
return fileNameAndContacts;
});
回答2:
I suggest doing RxAndroid2 in this way
// Init your dialog
ProgressDialog ringProgressDialog = new ProgressDialog(this);
ringProgressDialog.setTitle("Your Title");
ringProgressDialog.setMessage("Your message");
createDocument(filenameAndContacts)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(disposable -> ringProgressDialog.show())
.doOnTerminate(() -> {
if (ringProgressDialog.isShowing()) {
ringProgressDialog.dismiss();
}
})
.concatMap(fileAndContacts -> sendDocumentInEmail(fileAndContacts))
.subscribe(this::onSuccess, this::onError)
private void onSuccess() {
// Do anything you want on Android main thread
}
private void onError() {
// Timber..
}
Explanation
The method doOnSubscribe()
will be called whenever your observable start to subscribe and doOnTerminate()
will be called just before the resulting Observable
terminates, whether normally or with an error.
Then, if you want to do another thing like sendDocumentInEmail
after you get fileAndContacts
, just use concatMap()
So, whenever error happens, you can handle it in onError()
method.
Doing like this will help you avoid callback hell or side-effect, which easily lead you to error prone.
Reference:
http://reactivex.io/documentation/operators/do.html
https://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/
Hope this help
来源:https://stackoverflow.com/questions/45573892/progress-dialog-not-showing-up-before-rxjava-call