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

Android 11 Kotlin 如何在Fragment中实现后台位置定时获取

Android后台定时获取位置实现方案

你遇到的权限被拒问题核心是Android系统不允许直接申请后台定位权限,必须先申请前台定位权限,用户授权通过后才能申请后台定位权限,同时要实现2-3分钟的后台定时获取,不能依赖Fragment生命周期,需要适配系统后台保活规则。


1. 先配置AndroidManifest.xml权限

<!-- 基础定位权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- 前台服务权限(后台保活需要) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

<!-- 后台定位权限,Android 10及以上需要 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

2. 修正权限申请逻辑

不能直接申请后台权限,要按照「前台定位权限→后台定位权限」的顺序申请:

private val REQUEST_CODE_FOREGROUND_LOC = 101
private val REQUEST_CODE_BACKGROUND_LOC = 102
private var mFusedLocationClient: FusedLocationProviderClient? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext())
    checkLocationPermission()
}

private fun checkLocationPermission() {
    when {
        // 已经有后台权限,直接启动定时定位
        ActivityCompat.checkSelfPermission(
            requireContext(),
            Manifest.permission.ACCESS_BACKGROUND_LOCATION
        ) == PackageManager.PERMISSION_GRANTED -> {
            startPeriodicLocationTask()
        }
        // 有前台权限,申请后台权限
        ActivityCompat.checkSelfPermission(
            requireContext(),
            Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED -> {
            requestPermissions(
                arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                REQUEST_CODE_BACKGROUND_LOC
            )
        }
        // 没有前台权限,先申请前台
        else -> {
            requestPermissions(
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_CODE_FOREGROUND_LOC
            )
        }
    }
}

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(requireContext(), "权限被拒绝,无法使用定位功能", Toast.LENGTH_SHORT).show()
        return
    }
    when (requestCode) {
        REQUEST_CODE_FOREGROUND_LOC -> {
            // 前台权限申请成功,接下来申请后台权限
            checkLocationPermission()
        }
        REQUEST_CODE_BACKGROUND_LOC -> {
            // 后台权限申请成功,启动定时任务
            startPeriodicLocationTask()
        }
    }
}

3. 实现2-3分钟后台定时定位

Android系统后台会限制普通进程的定时任务,2-3分钟的高频定位建议配合前台Service实现,前台Service会在通知栏显示常驻通知,保证进程不被系统回收,以下是核心代码:

// 单次获取位置的方法
private fun getCurrentLocation() {
    val locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
    if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) 
        && !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
        Toast.makeText(requireContext(), "请开启定位服务", Toast.LENGTH_SHORT).show()
        return
    }
    if (ActivityCompat.checkSelfPermission(
            requireContext(),
            Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        return
    }
    val locationRequest = LocationRequest.create().apply {
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        interval = 120000 // 基础间隔2分钟
        fastestInterval = 120000
        maxWaitTime = 60000
    }
    val locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            super.onLocationResult(locationResult)
            locationResult.lastLocation?.let { location ->
                // 这里处理拿到的位置信息,比如上传到后台
                Log.d("定位结果", "纬度:${location.latitude} 经度:${location.longitude}")
            }
            // 用完移除回调避免内存泄漏
            mFusedLocationClient?.removeLocationUpdates(this)
        }
    }
    mFusedLocationClient?.requestLocationUpdates(
        locationRequest,
        locationCallback,
        Looper.getMainLooper()
    )
}

// 启动后台定时任务,这里用协程做示例,也可以用AlarmManager实现
private fun startPeriodicLocationTask() {
    lifecycleScope.launch(Dispatchers.IO) {
        while (isActive) {
            // 切主线程执行定位
            withContext(Dispatchers.Main) {
                getCurrentLocation()
            }
            // 每2.5分钟执行一次
            delay(150000)
        }
    }
}

注意事项

  • Android 12及以上,用户授予后台定位权限时必须选择「始终允许」,否则依然无法获取后台位置
  • 如果应用退到后台后定位中断,需要引导用户关闭系统的电池优化权限,允许应用后台活动
  • 如果需要长期后台运行,必须启动前台Service在Service中执行定时任务,Fragment生命周期有限,退到后台可能被销毁导致任务停止

内容的提问来源于stack exchange,提问作者Lavish Garg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:54:04