我试图将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)。很明显,这不是正在发生的事情,所以这个链的哪一部分确实在新线程上执行?
答案 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的调度程序被反转并且位置错误。