函数不在后台线程上执行

时间:2016-04-09 21:40:52

标签: android multithreading rx-java reactive-programming rx-android

我试图将RX应用到Android。我想要点击一个按钮,从网上下载并显示它。

我的问题是 HttpClient.connect()在mainThread 上执行,而不是在后台执行。 对HttpClient.connect()的调用作为传递给Observable.map()

的函数执行
Observable<Integer> dayDeltas =  Obs.obsToSequence(Obs.Observable(textView)); //transforms click events to observable
Observable<String> dates = dayDeltas.map(...).map(...)
dates.map(Obs.dateToWebPage()) // calls http.connect()
     .map(Obs.parseEvents())
     .observeOn(AndroidSchedulers.mainThread())
     .subscribeOn(Schedulers.newThread())
     .subscribe(updateTextView(textView));

public static Observable<Object> Observable(final TextView text) {
        return Observable.create(new Observable.OnSubscribe<Object>() {
            @Override
            public void call(final Subscriber<? super Object> subscriber) {
                final Object event = new Object();
                text.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.e("click", "click");
                        subscriber.onNext(event);
                    }
                });
            }
        });

现在我天真的解释是,因为我有 .subscribeOn(Schedulers.newThread()) observable上的每个函数/运算符都应该在一个新线程中执行,包括.map(f)。很明显,这不是正在发生的事情,所以这个链的哪一部分确实在新线程上执行?

2 个答案:

答案 0 :(得分:4)

subscribeOn会触发订阅副作用。在你的设置中,它将注册回调以捕获新线程上的按钮按下但是当按下发生时,onNext发射由主线程触发。然后,包括网络连接在内的链在主线程上执行。

您必须在连接方法之前放置一个新的observeOn(Schedulers.io()),以确保按钮按下事件的接收发生在主线程之外。

修改

//transforms click events to observable
Observable<Integer> dayDeltas =  Obs.obsToSequence(Obs.Observable(textView));

Observable<String> dates = dayDeltas.map(...).map(...)
dates
 .observeOn(Schedulers.io()) // <------------------------------------------ add
 .map(Obs.dateToWebPage()) // calls http.connect()
 .map(Obs.parseEvents())
 .observeOn(AndroidSchedulers.mainThread())
 //.subscribeOn(Schedulers.newThread()) // <------------------------------- remove
 .subscribe(updateTextView(textView));

答案 1 :(得分:2)

仔细阅读Scheduling and Threading RX doc后,我有了解决方案:

 dates
       .observeOn(Schedulers.io())
       .subscribeOn(AndroidSchedulers.mainThread())
       .map(Obs.dateToWebPage())

在我的原始代码中,传递给observeOn / subscribeOn的调度程序被反转并且位置错误。