You need to enable JavaScript to run this app. addOnSuccessListener内CompletableFuture.complete()失效致应用冻结
优惠活动
大模型
产品
解决方案
定价
更多

addOnSuccessListener内CompletableFuture.complete()失效致应用冻结

问题场景

编写如下获取位置的函数,希望在addOnSuccessListener监听器中完成CompletableFuture的结果返回:

private fun genericFunction(): CompletableFuture<Location?> {
    val completableFuture = CompletableFuture<Location?>()

    Executors.newCachedThreadPool().submit {
        val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        
        fusedLocationClient.lastLocation
                .addOnSuccessListener { location: Location? ->
                    Toast.makeText(...).show()
                    completableFuture.complete(location)
                }
    }
    
    return completableFuture
}

实际运行中观察到的现象:

  • 不等待该Future结果时,Toast可以正常弹出
  • 一旦等待该Future的结果,应用直接冻结
    最初的猜测是不能在addOnSuccessListener中调用completableFuture.complete(),但监听器内部可以正常访问该Future的引用,猜测逻辑存在矛盾。

问题根本成因

  • 之前的猜测方向完全错误:在成功监听器中调用completableFuture.complete()是完全合法的操作,不存在访问限制。
  • 触发冻结的核心是跨线程死锁,完整逻辑链:
    1. Android定位服务的FusedLocationProviderClient默认回调规则:如果调用addOnSuccessListener时没有显式指定执行Looper,会自动绑定到注册监听器时所在线程的Looper;如果当前线程没有绑定Looper(比如示例中用Executors.newCachedThreadPool()创建的无Looper的工作线程),系统会自动 fallback 到主线程Looper执行所有回调逻辑。
    2. 拿到返回的CompletableFuture后,通常是直接在主线程调用get()这类阻塞方法等待结果,这会直接挂起主线程,停止主线程Looper的消息循环。
    3. 此时定位服务的成功回调被排队到主线程消息队列中,但主线程已经被阻塞、不再消费队列任务,导致回调永远无法执行,completableFuture.complete()永远不会被触发,主线程和回调任务互相等待,最终表现为应用完全冻结。
  • 观察到的“不等待Future时Toast正常弹出”的现象刚好印证了这个逻辑:不阻塞主线程时,主线程Looper正常消费消息,回调可以顺利执行,Toast和complete()逻辑都能跑通。

调试定位方法

  • 冻结发生时,用Android Studio的Debug面板抓取全量Java线程堆栈:如果看到主线程堆栈停在CompletableFuture.get()的阻塞逻辑上,同时主线程消息队列中存在未执行的OnSuccessListener相关任务,即可直接确认死锁问题。
  • 在成功监听器的第一行加日志,打印当前执行线程的名称:Log.d("LocationDebug", "回调执行线程:${Thread.currentThread().name}"),大部分场景下会看到输出为main,验证定位回调最终运行在主线程的结论。
  • 对照测试:把阻塞等待Future结果的逻辑从主线程移到单独的工作线程执行,观察应用是否还会冻结——如果移走后冻结问题消失,就可以反向验证是主线程阻塞导致的回调无法执行。

内容的提问来源于stack exchange,提问作者Luca Dibattista

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.25 23:15:10