Bootstrap

kotlin定时器和主线程定时器

场景

最近要用kotlin写一个每隔一段时间切视频并截图

刷刷的就写出来了,很快啊

timerTask = object : TimerTask() {
    override fun run() {
        captureWindow()
        if ((group + 1) * 4 >= urls.size) {
            showDialog()
            timerTask.cancel()
            timer.cancel()
        }
        group++
        updatePlayers()
    }
}
timer = Timer()
timer.schedule(timerTask, 15000, 15000)

结果一运行就闪退了

Player is accessed on the wrong thread
java.lang.IllegalStateException: Player is accessed on the wrong thread.
Current thread: 'Timer-0'
Expected thread: 'main'

https://developer.android.com/media/media3/exoplayer/hello-world#a-note-on-threading

它意思是 Exoplayer 的实例必须从主线程访问,但是呢,我们现在是在定时器子线程(Timer-0)内部访问的

一直和单线程 js 打交道的人生,哪里懂得什么主线程子线程/(ㄒoㄒ)/~~

思路一

如果让子线程发送 Event 到主线程,由主线程响应,然后主线程去操作 Exoplayer,不就好了吗

悲伤的是,AI 写的代码驴头不对马嘴,只能自己去官方文档上现学。

https://kotlinlang.org/api/latest/jvm/stdlib/org.w3c.dom.events/-event-target/

结果搜了半天,发现唯一与 Event 有关的是“活动”

kotlin 好像和 js 这种不大一样,js 的核心就是处理事件和响应事件,但是 kotlin 不是为这方面设计的

不过我觉得往这个方向没问题,可能需要学习协程相关的吧

思路二

虽然没有 setInterval,但是 kotlin 是有等效于 setTimeout 的方法的
android.os.Handler 可以实现过一段事件执行某段代码

Handler(Looper.getMainLooper()).postDelayed(
    {
        captureWindow()
        if ((group + 1) * 4 >= urls.size) {
            showDialog()
        }
        group++
        updatePlayers()
    },
    15000
)

接着发挥传统艺能把 setTimeout 改写为 setInterval

    private fun updateEvery15s() {
        fun mySetTimeout() {
            Handler(Looper.getMainLooper()).postDelayed(
                {
                    captureWindow()
                    if ((group + 1) * 4 >= urls.size) {
                        showDialog()
                    } else {
                        group++
                        updatePlayers()
                        mySetTimeout()
                    }

                },
                if (group == 0) 20000 else 15000
            )
        }
        mySetTimeout()
    }

完成!

;