2014-07-23 12 views
1

我正在试验RxJava for Android。我正在尝试一个简单的例子,我试图在后台线程上卸载一个更长的操作,然后期待在主线程中返回并执行UI操作。AndroidObservable从来没有在主线程上观察

我从一个EditTextonTextChangeListener搜索文本(以一记漂亮的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的主线程中。

什么给?

+0

尝试在另一个线程上运行 –

+0

你的意思是尝试运行在.io线程以外的线程上吗?我实际上也尝试过'Schedulers.newThread()',但那不起作用。 如果我只坚持主线程,那么一切正常,但我想这将打败点,因为我明确地想要在非UI线程上运行操作,然后回调到UI线程。 –

回答

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,这就是为什么你会得到异常。

+0

就是你!我喜欢责怪可怕的语法(礼貌的Android不支持Java 8的功能),但事实是,我只是没有正确理解呼叫序列。谢谢你,欢呼! –

相关问题