Android主线程阻塞调用suspend方法避免runBlocking抛异常方案咨询
解决方案
方案1:自定义无中断runBlocking封装
如果你不想额外引入依赖,可以直接封装runBlocking逻辑,主动处理InterruptedException并清除线程中断标记,完全符合你不抛异常、不保留中断状态的需求:
fun <T> runBlockingIgnoreInterruption(block: suspend CoroutineScope.() -> T): T { var executionResult: T? = null var otherException: Throwable? = null val currentThread = Thread.currentThread() runBlocking { try { executionResult = block() } catch (interruptedEx: InterruptedException) { // 调用thread.interrupted()清除中断标记,不会向上传递中断状态 currentThread.interrupted() } catch (t: Throwable) { otherException = t } } otherException?.let { throw it } return executionResult!! }
调用方式:
val queryResult = runBlockingIgnoreInterruption { mySuspensionMethod() }
方案2:借助CompletableFuture实现阻塞调用
如果你可以引入coroutines jdk8扩展,可以直接将协程任务转为CompletableFuture后调用join方法,该方法默认不会抛出已检查的InterruptedException:
- 首先添加依赖:
// build.gradle (module level) dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.3" }
- 封装调用逻辑:
fun <T> runSuspendBlocking(block: suspend () -> T): T { return CoroutineScope(Dispatchers.IO).async { block() } .asCompletableFuture() .join() }
如果遇到线程中断,该方法会抛出未检查的CancellationException,你可以按需捕获处理即可,不需要操作线程中断标记。
重要提醒:两种方案均会阻塞主线程,仅可作为临时过渡方案使用,长期建议将旧Java代码改造为异步回调形式,避免主线程阻塞触发ANR导致应用崩溃。
内容的提问来源于stack exchange,提问作者Thomas Keller
相关产品推荐
相关产品推荐

