You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Getter中主线程调用ExoPlayer方法并正确获取返回值?

解决方案

前提判断

首先先确认你调用该Getter的线程:如果本身就是在主线程调用,不需要任何额外封装,直接返回属性即可:

val currentTrackIndex: Int
    get() = exoPlayer.currentIndex

如果是在子线程调用该Getter,需要同步获取结果,可以选择以下任意方案:


方案1:CountDownLatch实现(无额外依赖,兼容所有API版本)

利用CountDownLatch阻塞子线程,直到主线程执行完属性读取逻辑再返回结果,注意必须先做主线程判断避免死锁:

val currentTrackIndex: Int
    get() {
        // 主线程直接返回,避免死锁
        if (Looper.myLooper() == Looper.getMainLooper()) {
            return exoPlayer.currentIndex
        }
        var result = -1
        val latch = CountDownLatch(1)
        handler.post {
            result = exoPlayer.currentIndex
            latch.countDown()
        }
        latch.await()
        return result
    }

方案2:协程runBlocking实现(项目引入协程时优先选择)

你之前的runBlocking写法没有指定主线程调度器,所以不符合ExoPlayer的调用要求,修正后完全可以在生产环境使用:

val currentTrackIndex: Int
    get() {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            return exoPlayer.currentIndex
        }
        return runBlocking(Dispatchers.Main.immediate) {
            exoPlayer.currentIndex
        }
    }

注:runBlocking仅会阻塞当前调用线程,只要读取属性的耗时极短,不会带来性能问题,也符合生产环境使用规范


方案3:系统API实现(minSdk ≥ 23)

API 23及以上系统自带了postAndAwait方法,不需要自己实现阻塞逻辑:

val currentTrackIndex: Int
    get() {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            return exoPlayer.currentIndex
        }
        return handler.postAndAwait {
            exoPlayer.currentIndex
        }
    }

注意事项

  • 所有方案都必须加主线程判断,否则在主线程调用Getter时会触发死锁:主线程被阻塞,post到主线程的任务永远无法执行。
  • 不要在post到主线程的代码块中加入耗时操作,即使是在Service中,主线程阻塞超过5秒也会触发ANR,仅用来读取属性的场景完全符合要求。
  • 非必要场景下更推荐使用异步逻辑:直接把需要用到该属性的逻辑post到主线程执行,不需要阻塞线程,性能更优。

内容的提问来源于stack exchange,提问作者Milen Pivchev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:57:04