在Android上,一些回调总是在设计主Thread
上调用,例如以下ServiceConnection
:
private Completable dismissService() {
return Completable.fromEmitter(new Action1<CompletableEmitter>() {
@Override
public void call(final CompletableEmitter completableEmitter) {
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// here always main Thread...
unbindService(this);
completableEmitter.onCompleted();
}
@Override
public void onServiceDisconnected(ComponentName name) {
// no-op
}
};
completableEmitter.setCancellation(new AsyncEmitter.Cancellable() {
@Override
public void cancel() throws Exception {
unbindService(conn);
}
});
bindService(new Intent(MainActivity.this, MyService.class), conn, BIND_AUTO_CREATE);
}
});
}
但是,我希望dismissService()
返回的Completable在其调用的Thread
上发出结果。我使用newSingleThreadExecutor()
:
private Completable dismissServiceRetainingThread() {
return Single.fromCallable(new Callable<Thread>() {
@Override
public Thread call() throws Exception {
return Thread.currentThread();
}
}).flatMapCompletable(new Func1<Thread, Completable>() {
@Override
public Completable call(final Thread thread) {
return Completable.fromEmitter(new Action1<CompletableEmitter>() {
@Override
public void call(final CompletableEmitter completableEmitter) {
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// here always main Thread...
unbindService(this);
completableEmitter.onCompleted();
}
@Override
public void onServiceDisconnected(ComponentName name) {
// no-op
}
};
completableEmitter.setCancellation(new AsyncEmitter.Cancellable() {
@Override
public void cancel() throws Exception {
unbindService(conn);
}
});
bindService(new Intent(MainActivity.this, MyService.class), conn, BIND_AUTO_CREATE);
}
}).observeOn(Schedulers.from(
Executors.newSingleThreadExecutor(
new ThreadFactory() {
@Override
public Thread newThread(@NonNull Runnable runnable) {
return thread;
}
}
)));
}
});
}
然而,这与以下IllegalThreadStateException
崩溃:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.jenzz.rxjavathreadingtest, PID: 5307
java.lang.IllegalThreadStateException
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:930)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1348)
at java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:591)
at rx.internal.schedulers.ExecutorScheduler$ExecutorSchedulerWorker.schedule(ExecutorScheduler.java:79)
at rx.Completable$28$1.onCompleted(Completable.java:1805)
at rx.internal.operators.CompletableFromEmitter$FromEmitter.onCompleted(CompletableFromEmitter.java:73)
at com.jenzz.rxjavathreadingtest.MainActivity$5$2$1.onServiceConnected(MainActivity.java:117)
任何想法我如何能够跳回到之前在上游使用过的Thread
原版{使用subscribeOn(Schedulers.io())
?
答案 0 :(得分:2)
你不想回到你所在的确切线程。当同一Scheduler
中的其他线程空闲时,它可能很忙,除非它是主线程,否则无法保证在回调返回时它仍然存在。只要您的call
方法返回,它就可用于更多工作或清理。我想你想要的是在与原始呼叫相同的Scheduler
上执行。 AFIAK,没有直接的方法来确定线程的当前Scheduler
(确定一些调度程序有一种脆弱的方法,在本文的底部提到)。所以你不能轻易做你想做的事。默认通知主线程似乎是这种方法的理智行为。如果您希望默认使用其他Scheduler
,则可以使用.observeOn(Schedulers.io())
或您选择的调度程序。
如另一个答案所述,如果当前线程有一个looper,你可以尝试创建一个Handler
。您仍然会依赖调用者来确保在回调发生时该线程仍然可行。这似乎比告诉调用者响应将在主线程上出现更高级别的责任,除非他们使用observesOn
选择不同的响应。
最后一点想法是,可以通过查看线程的名称来确定Schedulers
返回的标准调度程序的正确调度程序。它们具有可预测的前缀,例如RxNewThreadScheduler-1
,因此一些String.startsWith()
调用可以隔离正确的调度。但这非常脆弱,因为它无法正确处理用户创建的调度程序,并且线程命名方案将来可能会发生变化。
答案 1 :(得分:0)
您可以尝试在Handler
中创建dismissService()
,然后在回调中,您可以回复相关的循环播放器。
仅当调用dismissService()
的线程是一个looper线程时才有效。
编辑:如果你特意试图在那个Scheduler
上做点什么。您也可以从Scheduler
创建一个工作人员,并以这种方式安排您的行动。