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

求助:实现Runtime Permission后位置权限回调反复触发问题

问题根源分析

你遇到的onRequestPermissionResult反复调用的死循环,核心原因是在onResume中无条件触发权限请求:

当用户勾选「不再询问」后,系统会直接拒绝权限请求并回调onRequestPermissionResult,而权限请求操作会触发Activity的生命周期回调(比如onResume再次执行),这样就形成了:
onResume → 请求权限 → onRequestPermissionResult → onResume → ... 的无限循环。

另外,当用户勾选「不再询问」后,系统不会再弹出权限请求弹窗,此时继续调用requestPermissions不仅无效,还会加剧循环问题。

修复方案

我会基于你提供的代码片段,给出完整的修复逻辑,核心是区分权限请求的不同状态,避免无意义的循环:

1. 完善权限检查方法

首先确保权限检查的逻辑正确:

private fun checkLocationPermission(): Boolean {
    return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}

2. 修改onResume逻辑,避免循环请求

在onResume中,我们需要先判断权限状态、用户是否勾选「不再询问」,再决定是执行业务逻辑、显示权限解释还是引导到设置页:

private val LOCATION_PERMISSION_REQUEST_CODE = 1001

override fun onResume() {
    super.onResume()
    if (checkLocationPermission()) {
        // 权限已授予,执行你的startL逻辑
        startL()
    } else {
        handleLocationPermissionRequest()
    }
}

private fun handleLocationPermissionRequest() {
    val shouldShowRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
    val prefs = getSharedPreferences("PermissionPrefs", MODE_PRIVATE)
    val hasRequestedPermission = prefs.getBoolean("hasRequestedLocationPermission", false)

    when {
        shouldShowRationale -> {
            // 用户之前拒绝过但没勾选「不再询问」,显示权限用途解释
            Snackbar.make(findViewById(android.R.id.content), "需要位置权限来获取您的位置信息,以便正常使用相关功能", Snackbar.LENGTH_SHORT)
                .setAction("知道了") {
                    requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
                }
                .show()
        }
        !hasRequestedPermission -> {
            // 第一次请求权限,直接发起请求
            requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
            prefs.edit().putBoolean("hasRequestedLocationPermission", true).apply()
        }
        else -> {
            // 用户已勾选「不再询问」,引导到应用设置页开启权限
            Snackbar.make(findViewById(android.R.id.content), "位置权限被拒绝且不再提示,请前往设置开启权限", Snackbar.LENGTH_INDEFINITE)
                .setAction("去设置") {
                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    val uri = Uri.fromParts("package", packageName, null)
                    intent.data = uri
                    startActivity(intent)
                }
                .show()
        }
    }
}

3. 正确处理onRequestPermissionResult回调

在回调中,我们只根据权限结果执行对应操作,不再触发新的权限请求:

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限授予成功,执行业务逻辑
            startL()
        } else {
            // 权限被拒绝,再次检查是否需要引导到设置页
            if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                // 用户勾选了「不再询问」,直接引导到设置
                Snackbar.make(findViewById(android.R.id.content), "需要位置权限才能正常使用,请前往设置开启", Snackbar.LENGTH_INDEFINITE)
                    .setAction("去设置") {
                        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                        val uri = Uri.fromParts("package", packageName, null)
                        intent.data = uri
                        startActivity(intent)
                    }
                    .show()
            } else {
                // 用户只是拒绝,没勾选不再询问,给出提示即可
                Snackbar.make(findViewById(android.R.id.content), "位置权限被拒绝,部分功能无法使用", Snackbar.LENGTH_SHORT).show()
            }
        }
    }
}
关键注意点
  • 避免在生命周期方法中无条件请求权限:onResume会在很多场景下触发(比如权限请求回调后、从设置页返回后),必须加状态判断;
  • 利用shouldShowRequestPermissionRationale区分用户状态:这个方法返回false时,要么是第一次请求权限,要么是用户勾选了「不再询问」,所以需要用SharedPreferences记录请求历史;
  • 用户勾选「不再询问」后,直接引导到设置页:此时系统不会再弹出权限弹窗,只能引导用户手动开启。

内容的提问来源于stack exchange,提问作者Ashiqul Islam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:26:15