Android:内容更改时 ContentObserver onChange() 的奇怪行为

问题描述

我已经检查了有关 ContentObserver 的其他问题,但没有找到解决方案。

我想在 STREAM_MUSIC 的音量发生变化时立即获得回调。不仅在按下音量按钮时,而且在通过例如以编程方式更改音量时音频管理器。 问题是, onChange() 并不总是被调用,只是偶尔被调用。我下面的测试有时会失败,有时会成功(即使我等了 10 秒)。 我做错了什么?

最小工作示例: 内容观察者:

class AudioContentObserver(
    private val context: Context,) : ContentObserver(Handler(HandlerThread("AudioContentObserverThread").apply { start() }.looper)) {
    
    private val audioManager = context.getSystemService(Context.AUdio_SERVICE) as? AudioManager
    private var lastVolIndex: Int = -1
    var onChangeCalled = false

    override fun onChange(selfChange: Boolean) = this.onChange(selfChange,null)

    override fun onChange(selfChange: Boolean,uri: Uri?) {
        audioManager ?: return
        val volIndex = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
        if (volIndex == lastVolIndex) return // onChange() triggered by other system setting update
        println("onChange() called!")
        onChangeCalled = true
    }

    fun registerObserver() {
        audioManager ?: return
        // no URI just for volume changes,so listen to all system setting changes
        context.contentResolver.registerContentObserver(
            android.provider.Settings.System.CONTENT_URI,true,this
        )
        lastVolIndex = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
    }

    fun unregisterObserver() {
        audioManager ?: return // ContentObserver was never registered
        context.contentResolver.unregisterContentObserver(this)
    }
}

这是我的测试:

import android.content.Context
import android.media.AudioManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.awaitility.Duration
import org.awaitility.kotlin.atMost
import org.awaitility.kotlin.await
import org.awaitility.kotlin.untilAsserted
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class AudioContentObserverTest {

    lateinit var context: Context
    lateinit var observer: AudioContentObserver

    @Before
    fun setup() {
        context = ApplicationProvider.getApplicationContext<Context>()
        observer = AudioContentObserver(context)
    }

    @After
    fun cleanup() {
        observer.unregisterObserver()
    }

    @Test
    fun should_get_onChange_callback_when_volume_changes() {
        val audioManager: AudioManager =
            context.getSystemService(Context.AUdio_SERVICE) as AudioManager

        // set volume index to 1 before we register ContentObserver
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,1,AudioManager.FLAG_SHOW_UI)
        observer.registerObserver()
        // changing volume while ContentObserver observes CONTENT_URI
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,2,AudioManager.FLAG_SHOW_UI)
        // timeout after 2 sec if onChange() was not called
        await atMost Duration.TWO_SECONDS untilAsserted { Assert.assertTrue(observer.onChangeCalled) }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)