Android Kotlin相机权限问题及弹窗BUG技术求助
问题描述
我正在开发一款基于Android Kotlin的相机目标检测应用,目前遇到以下问题:
- 授予相机权限后应用显示黑屏,需重启1-2次才能成功打开相机;
- 自定义权限提示弹窗存在两个BUG:
- 用户点击弹窗“OK”后仍拒绝相机权限,应用会进入弹窗反复弹出的循环;
- 初始拒绝权限后,通过弹窗“OK”授予权限时应用意外关闭。
相关代码
onCreate函数
if (ContextCompat.checkSelfPermission( this, android.Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED ) requestPermissions(arrayOf(android.Manifest.permission.CAMERA), 101) else detectObject()
权限处理函数
fun getPermission() { if (ContextCompat.checkSelfPermission( this, android.Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED ) { requestPermissions(arrayOf(android.Manifest.permission.CAMERA), 101) } else { detectObject() } } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 101 && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { detectObject() } else { val alert = PermissionDialog() alert.show(supportFragmentManager, null) } }
权限弹窗Dialog类
import android.app.AlertDialog import android.app.Dialog import android.media.MediaPlayer import android.os.Bundle import android.widget.Toast import androidx.fragment.app.DialogFragment import com.example.sightfulkotlin.MainActivity import com.example.sightfulkotlin.R class PermissionDialog : DialogFragment() { private lateinit var mediaPlayer: MediaPlayer override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(activity) builder .setTitle("Camera Permission") .setIcon(android.R.drawable.ic_menu_camera) .setMessage("Camera permission denied") .setPositiveButton("Ok") { _, _ -> (activity as MainActivity).getPermission()} .setNegativeButton("Cancel") { _, _ -> Toast.makeText(context, "Sorry, we can't make the app work without the camera permission.", Toast.LENGTH_LONG).show() } .setCancelable(false) return builder.create() } }
解决方案
1. 黑屏问题修复
黑屏多因权限授予后相机预览未正确初始化或重启,需确保detectObject()方法处理好相机资源的释放与重建:
- 在
detectObject()开头添加资源释放逻辑,避免旧资源占用导致新预览无法启动:
private fun detectObject() { // 先释放已绑定的相机资源 cameraProvider?.unbindAll() // 重新初始化相机预览与目标检测逻辑 // ... 原有业务代码 }
- 确保
onRequestPermissionsResult中调用detectObject()时在主线程执行,避免UI阻塞导致预览启动失败。
2. 权限弹窗BUG修复
(1)弹窗循环问题
当用户拒绝权限并勾选「不再询问」时,直接调用requestPermissions()会触发权限回调并重复弹出弹窗,需先判断是否需要显示解释弹窗:
修改onRequestPermissionsResult逻辑:
override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 101) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { detectObject() } else { // 判断用户是否勾选了「不再询问」 val shouldShowRationale = shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA) if (shouldShowRationale) { // 用户仅拒绝权限,未勾选不再询问,显示弹窗 val alert = PermissionDialog() alert.show(supportFragmentManager, null) } else { // 用户勾选不再询问,引导至应用设置页开启权限 Toast.makeText(this, "请在应用设置中开启相机权限", Toast.LENGTH_LONG).show() } } } }
(2)应用意外关闭问题
崩溃原因多为(activity as MainActivity)强转失败(Activity已销毁时),修改弹窗点击事件的安全转换逻辑:
// 在PermissionDialog中替换PositiveButton的点击处理 .setPositiveButton("Ok") { _, _ -> context?.let { ctx -> (ctx as? MainActivity)?.getPermission() ?: run { Toast.makeText(ctx, "无法获取权限,请重启应用", Toast.LENGTH_SHORT).show() } } }
同时在MainActivity销毁时清理弹窗,避免内存泄漏:
override fun onDestroy() { supportFragmentManager.findFragmentByTag(null)?.let { fragment -> (fragment as? DialogFragment)?.dismiss() } super.onDestroy() }
内容的提问来源于stack exchange,提问作者Fatema Shawki
相关产品推荐
相关产品推荐

