我正在实施一个可观察到的Resource
。
问题是这个资源真的不喜欢从它创建的不同线程关闭(它会杀死一只小狗并在发生这种情况时抛出异常)。
当我处理订阅时,从Cancellable
线程调用资源Disposable
/ main
,而Schedulers.io()
订阅了observable。
这是Kotlin代码:
fun lines(): Observable<String> =
Observable.create { emitter ->
val resource = NetworkResource()
emitter.setCancellable {
resource.close() // <-- main thread :(
}
try {
while (!emitter.isDisposed)
emitter.onNext(resource.readLine()) // <-- blocked here!
} catch (ioe: IOException) {
emitter.tryOnError(ioe) // <-- this also triggers the cancellable
}
}
val disposable = lines()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { Log.i(TAG, "Line: $it" }
disposable.dispose() // <-- main thread :)
问题:是否可以从正确的*主题中调用Cancellable
,同时考虑到resource.readLine()
上的订阅主题已被屏蔽?
*正确的线程意味着subscribeOn(Schedures.io())
中的那个。
编辑:我担心这个问题没有正确的答案,除非resource.close()
是线程安全的,或者resource.dataReady
上的某种轮询已经实现,以便线程未被阻止。
答案 0 :(得分:2)
Schedulers.io()
管理线程池,因此它可能会也可能不会使用相同的线程来处置您的资源。您必须使用自定义调度程序和unsubscribeOn()
运算符,以确保在同一个线程上订阅和取消订阅Observable
。类似的东西:
Scheduler customScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
val disposable = lines()
.unsubscribeOn(customScheduler)
.subscribeOn(customScheduler)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { Log.i(TAG, "Line: $it" }
答案 1 :(得分:1)
如果您不介意稍微延迟拨打NetworkResource#close
,为什么不呢
fun lines(): Observable<String> =
Observable.create { emitter ->
val resource = NetworkResource()
try {
while (!emitter.isDisposed) {
emitter.onNext(resource.readLine())
}
resource.close()
} catch (ioe: IOException) {
emitter.tryOnError(ioe)
}
}
但是仍有一个问题:如果IOException
,任何人都不会打电话给NetworkResource#close
(我也认为这个问题的例子也是如此)。
尝试解决此问题:
fun lines(): Observable<String> =
Observable.create { emitter ->
val resource = NetworkResource()
try {
while (!emitter.isDisposed) {
emitter.onNext(resource.readLine())
}
} catch (ioe: IOException) {
emitter.tryOnError(ioe)
} finally {
resource.close() // try-catch here, too?
}
}
或使用&#34; Kotlin-Try-With-Resources&#34;函数use
fun lines(): Observable<String> =
Observable.create { emitter ->
NetworkResource().use { resource ->
try {
while (!emitter.isDisposed) {
emitter.onNext(resource.readLine())
}
} catch (ioe: IOException) {
emitter.tryOnError(ioe)
}
}
}
我希望,这有帮助。祝你周末愉快。
答案 2 :(得分:0)
如何选择其他途径?
a)通过制作NetworkResource
线程安全(如果您控制源代码)
或
b)通过将NetworkResource
与&#34;代理&#34; 包装在一起?使用&#34; agent&#34;我的意思是一个内部使用专用线程的代理,它与NetworkResource
进行所有交互(构造,readLine,close,...)