AndroidObservable永远不会在主线程上观察

时间:2014-07-23 02:39:19

标签: android multithreading rx-java

我正在试验RxJava for Android。我尝试了一个简单的例子,我尝试在后台线程上卸载更长的操作,然后期望返回主线程并执行ui操作。

我从EditText onTextChangeListener(通过漂亮的ButterKnife注入)获取搜索文本,然后将其拍摄到长时间运行的操作_searchForContacts(searchText),该操作返回联系人列表对象。然后,我通过在适配器上设置信息并通知数据集更改来继续更新我的视图。

但是,在尝试进行任何ui更新时遇到异常,因为我从不在主线程上。

这是我的代码:

public class MyTestFragment
    extends Fragment
    implements Observer<List<Contact>> {

    // ...

    private Subscription _searchGuestsSubscription = Subscriptions.empty();

    // ...

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        _searchGuestsSubscription.unsubscribe();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        _adapter = new ContactImportAdapter();
        _adapter.setContacts(_searchForContacts(ALL_CONTACTS));
        _listView.setAdapter(_adapter);
    }

    @Override
    public void onNext(List<Contact> contactSearchResults) {
        Timber.d("I'm on the main thread -> " + String.valueOf(Looper.myLooper() == Looper.getMainLooper()));
        _adapter.setContacts(contactSearchResults);
    }

    @Override
    public void onCompleted() {
        _updateView();
    }

    @Override
    public void onError(Throwable e) {
        Timber.e(e, "Oops something went wrong.");
    }

    // ButterKnife ~ onTextChangeListener
    @OnTextChanged(R.id.search_edit_text)
    void onSearchContact(CharSequence searchChars) {
        _searchGuestsSubscription = AndroidObservable.bindFragment(this,
                                                                   _searchGuestsObservable(searchChars.toString()))
                                                     // The below line doesn't seem to have any effect?
                                                     .observeOn(AndroidSchedulers.mainThread())
                                                     .subscribeOn(Schedulers.io())
                                                     .subscribe(this);
    }

    private Observable<List<Contact>> _searchGuestsObservable(final String searchText) {
        return Observable.create(new Observable.OnSubscribe<List<Contact>>() {


            @Override
            public void call(Subscriber<? super List<Contact>> searchResultObserver) {
                // do the search
                List<Contact> contactSearchResults = _searchForContacts(searchText);
                onNext(contactSearchResults);
                onCompleted();
            }
        });
    }

    private void _updateView() {
        _adapter.notifyDataSetChanged();
    }
}

它表示始终在后台线程上调用onNext。我得到了通常的IllegalStateException: The current thread must have a looper!例外。日志语句还表明我不在onNext内的主线程上。

是什么给出了?

1 个答案:

答案 0 :(得分:1)

您的问题似乎来自于您直接在Fragment中调用onNext而不是调用订阅者的onNext这一事实。

更改您的代码。

private Observable<List<Contact>> _searchGuestsObservable(final String searchText) {
    return Observable.create(new Observable.OnSubscribe<List<Contact>>() {
        @Override
        public void call(Subscriber<? super List<Contact>> searchResultObserver) {
            // do the search
            List<Contact> contactSearchResults = _searchForContacts(searchText);
            searchResultObserver.onNext(contactSearchResults);
            searchResultObserver.onCompleted();
        }
    });
}

当你的Observable.OnSubscribe<List<Contact>>()被执行时,你当然是在后台线程上因为subscribeOn(Schedulers.io())并且你自己调用你的片段onNext,这就是你得到那个例外的原因。