Android实现SeekBar亮度调节与系统亮度变化检测同步问题
问题描述
在Android应用中实现了SeekBar调节系统亮度,同时监听系统亮度变化同步到SeekBar,但部分小米设备(如Redmi Note7)的亮度范围为0-4000,与官方文档定义的0-255不符,且无公开API可获取亮度最大值,导致双向同步功能失效。
原调节亮度代码:
binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { @RequiresApi(api = Build.VERSION_CODES.M) override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { val permission = Settings.System.canWrite(applicationContext) if (permission) { var brightnessValue = p1 * 255 / 100 Settings.System.putInt( applicationContext.contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) Settings.System.putInt(contentResolver, SCREEN_BRIGHTNESS, brightnessValue) binding.seekBar.progress = brightnessValue } else { val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS) intent.data = Uri.parse("package:" + applicationContext.packageName) startActivityForResult(intent, 0) } } override fun onStartTrackingTouch(p0: SeekBar?) { } override fun onStopTrackingTouch(p0: SeekBar?) { } })
原监听亮度变化代码:
val contentObserver: ContentObserver = object : ContentObserver(Handler()) { override fun onChange(selfChange: Boolean) { val a = Settings.System.getInt(contentResolver, SCREEN_BRIGHTNESS, 0) Log.d("MainActivity", "Brightness value: $a") binding.seekBar.progress = a* 255 / 100 } } contentResolver.registerContentObserver( Settings.System.getUriFor(SCREEN_BRIGHTNESS), false, contentObserver )
解决方案
核心思路是通过比例映射适配设备实际亮度范围,避免依赖硬编码的最大值,同时加入状态标记避免循环同步。
1. 获取设备实际亮度最大值
由于无公开API,通过写入大值再读取的方式获取设备支持的亮度上限:
private fun getMaxBrightness(): Int { val resolver = contentResolver // 尝试写入一个足够大的值 Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS, 4000) // 读取实际生效的最大值 return Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS, 255) }
2. 修正SeekBar调节逻辑
将SeekBar固定为0-100的用户友好范围,通过比例转换为设备实际亮度值,同时关闭自动亮度避免冲突:
private var isUpdatingFromApp = false // 标记是否为应用内部修改亮度 val maxBrightness = getMaxBrightness() binding.seekBar.max = 100 // 设置SeekBar进度范围为0-100 binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { @RequiresApi(api = Build.VERSION_CODES.M) override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { if (!fromUser) return // 非用户操作直接返回,避免循环同步 val permission = Settings.System.canWrite(applicationContext) if (permission) { // 关闭自动亮度模式,确保手动调节生效 Settings.System.putInt( contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL ) isUpdatingFromApp = true // 将SeekBar进度转换为设备实际亮度值 val brightnessValue = (progress * maxBrightness / 100).coerceIn(0, maxBrightness) Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightnessValue) isUpdatingFromApp = false } else { val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS) intent.data = Uri.parse("package:" + applicationContext.packageName) startActivityForResult(intent, 0) } } override fun onStartTrackingTouch(p0: SeekBar?) {} override fun onStopTrackingTouch(p0: SeekBar?) {} })
3. 修正亮度监听同步逻辑
监听系统亮度变化时,将实际亮度值转换为SeekBar的0-100进度,同时跳过应用内部修改的触发:
val contentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { override fun onChange(selfChange: Boolean) { if (isUpdatingFromApp) return // 跳过应用内部修改的同步 val currentBrightness = Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, 0) // 将实际亮度值转换为SeekBar进度 val progress = (currentBrightness * 100 / maxBrightness).coerceIn(0, 100) binding.seekBar.progress = progress } } contentResolver.registerContentObserver( Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, contentObserver )
4. 销毁时清理资源
在Activity销毁时注销ContentObserver,避免内存泄漏:
override fun onDestroy() { super.onDestroy() contentResolver.unregisterContentObserver(contentObserver) }
内容的提问来源于stack exchange,提问作者Halil Ozel
相关产品推荐
相关产品推荐

