我有一个调用web服务的方法,我认为它正在IO线程上运行,直到服务停止并且UI冻结。
所以我开始了一些简单的测试来检查线程
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.8'
public void test() {
disposableRx.add(
Observable.just(1, 2)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println("Emitting item on: " + Thread.currentThread().getName());
}
})
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(@NonNull Integer integer) throws Exception {
System.out.println("Processing item on: " + Thread.currentThread().getName());
return integer * 2;
}
})
.subscribeWith(new DisposableObserver<Integer>() {
@Override
public void onNext(@NonNull Integer integer) {
System.out.println("Consuming item on: " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
})
);
}
导致以下输出指示主线程上的所有内容都在运行,尽管已订阅并观察?
Emitting item on: main
Processing item on: main
Consuming item on: main
Emitting item on: main
Processing item on: main
Consuming item on: main
BUT 如果我将observeOn移动到.subscribeWith之前,如下所示......
public void test() {
disposableRx.add(
Observable.just(1, 2)
.subscribeOn(Schedulers.io())
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println("Emitting item on: " + Thread.currentThread().getName());
}
})
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(@NonNull Integer integer) throws Exception {
System.out.println("Processing item on: " + Thread.currentThread().getName());
return integer * 2;
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<Integer>() {
@Override
public void onNext(@NonNull Integer integer) {
System.out.println("Consuming item on: " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
})
);
}
输出是我正在寻找的东西,即使在阅读了许多关于RxJava的博客后,我必须说这让我感到困惑。
Emitting item on: RxCachedThreadScheduler-1
Processing item on: RxCachedThreadScheduler-1
Emitting item on: RxCachedThreadScheduler-1
Processing item on: RxCachedThreadScheduler-1
Consuming item on: main
Consuming item on: main
我已经删除了我的原始方法,直到它几乎是博客文章中的示例方法的副本
这意味着这应该在IO线程上运行loadPerson(),在主线程上发出。它没有。
disposableRx.add(
repo.loadPersonProfile(id).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableMaybeObserver<String>() {
@Override
public void onSuccess(@NonNull String response) {
loadPersonDetailsResponse.setValue(ViewModelResponse.success(response));
isLoading.setValue(false);
}
@Override
public void onError(@NonNull Throwable e) {
loadPersonDetailsResponse.setValue(ViewModelResponse.error(e));
isLoading.setValue(false);
}
@Override
public void onComplete() {
}
})
);
从我的方法中转出线程表明它在主线程上运行?
造成这种情况的原因是什么?
答案 0 :(得分:6)
订单,其中observeOn()
和sunbscribeOn()
以及其他运营商非常重要。
subscribeOn()
运算符告诉源Observable 要发出和转换项目的线程。
小心放置observeOn()运算符的位置,因为它会发生变化 执行工作的线程!在大多数情况下,您可能想要延迟 切换到观察线程直到你的Rx链的最后。
Observable.just("long", "longer", "longest")
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.map(String::length)
.filter(length -> length == 6)
.subscribe(length -> System.out.println("item length " + length));
这里的地图,过滤和消费是在主线程
中执行的observeOn()
之前 map()
没有理由在map()运算符上方应用observeOn()运算符。
实际上,这段代码会导致NetworkOnMainThreadException!我们不想在主线程上读取HTTP响应 - 它应该在我们切换回主线程之前完成。
您还可以使用多个observeOn()来切换此示例中的线程。
Observable.just("long", "longer", "longest")
.doOnNext(s -> System.out.println("first doOnNext: processing item on thread " + Thread.currentThread().getName()))
.observeOn(Schedulers.computation())
.map(String::toString)
.doOnNext(s -> System.out.println("second doOnNext: processing item on thread " + Thread.currentThread().getName()))
.observeOn(Schedulers.io())
.map(String::toString)
.subscribeOn(Schedulers.newThread())
.map(String::length)
.subscribe(length -> System.out.println("received item length " + length + " on thread " + Thread.currentThread().getName()));
输出:
first doOnNext: processing item on thread RxNewThreadScheduler-1
first doOnNext: processing item on thread RxNewThreadScheduler-1
first doOnNext: processing item on thread RxNewThreadScheduler-1
second doOnNext: processing item on thread RxComputationThreadPool-1
second doOnNext: processing item on thread RxComputationThreadPool-1
second doOnNext: processing item on thread RxComputationThreadPool-1
received item length 4 on thread RxCachedThreadScheduler-1
received item length 6 on thread RxCachedThreadScheduler-1
received item length 7 on thread RxCachedThreadScheduler-1
注意强>
根据此answer subscribeOn()
不适用于下游运算符,因此它不保证您的操作将在不同的线程上。
subscribeOn
效果向上游靠近源头 事件
至于你的问题,我做了一个测试,这是结果
private void testRxJava2Async() {
io.reactivex.Observable.fromCallable(new Callable<String>() {
@Override
public String call() throws Exception {
Log.d(TAG,"callable (expensive assync method) was called on --> "+Thread.currentThread().getName());
return null;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.d(TAG,"onNext() was called on --> "+Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
测试结果:
callable (expensive assync method) was called on --> RxCachedThreadScheduler-1
onNext() was called on--> main
答案 1 :(得分:2)
希望这是有道理的。 RX框架很棒。但实际上需要现场练习才能做到正确。你见过第一手了。
要确保在主线程上推送和执行更改,您需要执行的是添加中间步骤以观察更改。
subscribeOn
这个想法是observeOn
只接受开始处理,例如NetworkRequest,但不保证将值推送到同一个线程。 resource odbc_connect ( string $dsn , string $user , string $password [, int $cursor_type ] )
<?php
// Microsoft SQL Server using the SQL Native Client 10.0 ODBC Driver - allows connection to SQL 7, 2000, 2005 and 2008
$connection = odbc_connect("Driver={SQL Server Native Client 10.0};Server=$server;Database=$database;", $user, $password);
// Microsoft Access
$connection = odbc_connect("Driver={Microsoft Access Driver (*.mdb)};Dbq=$mdbFilename", $user, $password);
// Microsoft Excel
$excelFile = realpath('C:/ExcelData.xls');
$excelDir = dirname($excelFile);
$connection = odbc_connect("Driver={Microsoft Excel Driver (*.xls)};DriverId=790;Dbq=$excelFile;DefaultDir=$excelDir" , '', '');
?>
嘿,我可以收到您最初订阅的那些值。因此,为了确保在主线程上转换值,您可以观察另一个纯线程的更改,执行操作(Map | Flatmap等),然后观察这些更改,这将保证只有那些值放在主线程上。基本上你的意思就是这个,嘿执行那些线程中所有繁重的处理,但是嘿嘿计算完成后,在主线程中将这些值传递给我继续我的工作,只有这样才能接受,因此没有工作会永远都要在主线上完成。