I show a DialogFragment
and load data in the background. I want the dialog to show up, the data keeps on loading and incrementally updates the already visible dialog.
Problem
The dialog is not shown before the observable completes. Why?
Code
private final static Handler mHandler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Observable<List<Data>> observable = Observable.create(new Observable.OnSubscribe<Data>()
{
@Override
public void call(Subscriber<? super Data> subscriber)
{
// iterate and create data
for (int i = resolveInfo.size() - 1; i >= 0; i--)
{
Data d = ...;
subscriber.onNext(d);
}
subscriber.onCompleted();
}
})
.onBackpressureBuffer()
.buffer(150, TimeUnit.MILLISECONDS)
.filter(new Func1<List<Data>, Boolean>()
{
@Override
public Boolean call(List<Data> rxSingleDatas)
{
return rxSingleDatas.size() > 0; // only deliver not emtpy lists!
}
})
.onBackpressureBuffer()
.doOnNext(new Action1<List<Data>>()
{
@Override
public void call(List<Data> shareDatas)
{
// add result to list + notify adapter
for (int i = 0; i < shareDatas.size(); i++)
mData.add(shareData);
if (mAdapter != null)
mAdapter.notifyDataSetChanged();
}
})
.doOnCompleted(new Action0()
{
@Override
public void call()
{
// flag to indicate all data is loaded
mReady = true;
}
});
// subscribe on handler thread for async execution
// observe on main thread for updating UI
mSubscription = observable
.subscribeOn(HandlerScheduler.from(mHandler))
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
}
@Override
public void onDestroy()
{
if (mSubscription != null)
mSubscription.unsubscribe();
super.onDestroy();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity())
.title(R.string.share_with)
.cancelable(true)
.autoDismiss(false);
mAdapter = ...;
builder
.adapter(mAdapter, new MaterialDialog.ListCallback() {
@Override
public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence charSequence) {
if (!mReady)
return;
// handle click
}
});
MaterialDialog dlg = builder.build();
return dlg;
}
EDIT
I replaced the handler with one that's running on the background thread, but this leads to following execption: CalledFromWrongThreadException
when trying to update the adapter in the doOnNext
call... I would say the observeOn
should have the effect that the doOnNext
is called on the main thread, but it seems, that this does not work...
There was a little confusion about how subscribeOn
and observeOn
operators work.
subscribeOn()
applies the thread to the generating part (Observable.create()
here) and whatever goes after it until the first observeOn()
or an operator that operates on a specific thread by design. Thus, observeOn
switches the thread for operations downstream of it in the chain. RxJava doesn't automatically switch threads until explicitly told to.