Android中使用CompletableFuture避免UI线程阻塞的实现方案
问题描述
在我的Android应用中,出于学习目的,我希望使用java.util.concurrent工具实现带返回值的操作。了解到CompletableFuture可用于该场景后,我编写了一个模拟耗时操作的项目:
class MyRepository { private var counter = 0 // 模拟阻塞调用 fun makeRequest(): Int { Thread.sleep(2000L) counter += 1 return counter } }
随后我在UI线程中调用以下函数:
fun getNumber(): Int { val completableFuture = CompletableFuture<Int>() Executors.newCachedThreadPool().submit<Any?> { val result = myRepository.makeRequest() completableFuture.complete(result) null } return completableFuture.get() }
执行该操作时UI会被阻塞,请问如何仅使用java.util.concurrent工具,通过CompletableFuture实现此类操作且不阻塞应用UI?
解决方案
代码中UI阻塞的核心原因是调用了completableFuture.get()——这个方法是阻塞式的,会让当前的UI线程一直等待异步任务完成,直接导致UI卡顿甚至ANR。
要解决这个问题,必须放弃同步返回结果的写法,改用CompletableFuture的异步回调机制,让任务完成后再通知UI线程更新界面,而非让UI线程主动等待。
核心修改点
- 移除UI线程中的
get()调用 - 使用
thenAccept()/thenApply()等异步回调方法处理结果 - 更新UI的逻辑必须切回UI线程(利用Android的
runOnUiThread()或Handler)
示例实现(简洁版)
// 定义接收结果的Lambda参数,替代同步返回 fun getNumber(onResult: (Int) -> Unit) { // 使用supplyAsync直接创建异步任务,替代手动提交+CompletableFuture初始化 CompletableFuture.supplyAsync({ myRepository.makeRequest() }, Executors.newCachedThreadPool()) // 任务完成后执行回调 .thenAccept { result -> // 切回UI线程更新界面 runOnUiThread { onResult(result) } } } // 在UI线程调用示例 getNumber { result -> // 这里直接写UI更新逻辑,比如给TextView赋值 resultTextView.text = "请求结果:$result" }
关键说明
supplyAsync()是CompletableFuture提供的便捷方法,自动在指定线程池执行任务并返回结果,比手动创建CompletableFuture+提交线程更简洁thenAccept()会在异步任务完成后触发,它默认运行在任务所在的线程池,因此必须通过runOnUiThread()切换回UI线程执行界面更新- 绝对禁止在UI线程调用
get()、join()这类阻塞方法,这是Android异步编程的基本准则
内容的提问来源于stack exchange,提问作者faritowich
相关产品推荐
相关产品推荐

