Android实现定位功能(附带源码)

Android 实现定位功能 —— 从基础到实战的完整项目解析

本文将深入探讨 Android 平台的定位功能,涵盖 GPS、Wi-Fi、蜂窝网络、FusedLocationProvider(FLP)等技术,并完整实现一个支持前后台运行的高精度定位系统,适用于地图导航、打卡签到、骑行记录、物联网设备等应用场景。


一、项目介绍

1.1 需求背景

在移动应用中,获取设备位置信息是常见需求,如:

  • 地图导航(如 Google Maps、高德地图)

  • 打卡签到(如考勤、健身记录)

  • LBS 服务(如外卖、网约车)

  • 运动轨迹(如骑行、跑步、徒步记录)

要想在 Android 上实现精准、稳定、高效的定位,需要结合多种技术手段,并充分考虑 功耗、权限管理、系统兼容性 等问题。


1.2 本项目目标

本项目的核心目标:

实现一个支持前后台持续运行的高精度定位服务,采用 FusedLocationProvider(FLP),并结合 WorkManager 确保后台存活,最终可通过通知栏实时显示位置信息,并定期上传到服务器。

关键功能点:

✅ 使用 FusedLocationProvider(FLP) 获取高精度位置
✅ 支持 GPS、Wi-Fi、蜂窝网络 结合定位
✅ 支持 后台运行,避免熄屏或切换 App 时定位中断
✅ 使用 前台服务(Foreground Service) 保持存活
✅ 通过 通知栏显示位置,让用户随时掌握位置状态
✅ 支持 定时上传位置到服务器(可选)
✅ 兼容 Android 6.0+(动态权限)、Android 10+(后台定位限制)、Android 12+(精确/模糊定位)


二、定位相关技术知识解析

2.1 Android 位置获取方式

方式说明优势劣势
GPS通过卫星获取位置精度高(可达 5-10m),适合户外耗电高,室内无效
Wi-Fi通过附近 Wi-Fi 进行定位适合室内,速度快,省电精度较低(30-50m),依赖网络
蜂窝网络通过基站定位适用于无 Wi-Fi 场景精度低(100-1000m)
FusedLocationProvider(推荐)Google 提供的高精度定位 API,融合 GPS、Wi-Fi、蜂窝自动切换,精准、省电,适合大多数应用需要 Google Play 服务,部分国产 ROM 可能受限

2.2 定位权限解析

Android 6.0+ 需要动态申请权限,否则 SecurityException

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

Android 10+ 限制

  • 后台定位需要 ACCESS_BACKGROUND_LOCATION

  • 仅申请 ACCESS_FINE_LOCATION 在后台无效

Android 12+ 变化

  • 需要 精准(Fine)和模糊(Coarse)定位权限

  • 精确权限:ACCESS_FINE_LOCATION

  • 模糊权限:ACCESS_COARSE_LOCATION


三、项目实现思路

3.1 关键实现方案

  1. 使用 FusedLocationProvider(FLP)获取高精度位置

  2. 使用 Foreground Service(前台服务)保持后台存活

  3. 通过 WorkManager 实现后台定时上传位置

  4. 在通知栏显示当前位置信息

3.2 关键组件

组件作用
FusedLocationProviderClient位置获取
Foreground Service保持后台运行
NotificationManager通知栏显示定位状态
WorkManager定时上传数据

四、完整整合代码(含详细注释)

4.1 AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.locationtracker">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

    <application
        android:label="定位演示"
        android:icon="@mipmap/ic_launcher">
        
        <service
            android:name=".LocationService"
            android:foregroundServiceType="location" />
            
        <activity android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

    </application>
</manifest>

4.2 MainActivity.kt

class MainActivity : AppCompatActivity() {

    private val permissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
            val allGranted = result.values.all { it }
            if (allGranted) {
                startLocationService()
            } else {
                Toast.makeText(this, "未授予全部定位权限", Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 动态申请权限
        permissionLauncher.launch(arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_BACKGROUND_LOCATION
        ))
    }

    private fun startLocationService() {
        val intent = Intent(this, LocationService::class.java)
        ContextCompat.startForegroundService(this, intent)
    }
}

4.3 LocationService.kt

class LocationService : Service() {

    private lateinit var fusedClient: FusedLocationProviderClient
    private lateinit var locationRequest: LocationRequest

    override fun onCreate() {
        super.onCreate()
        fusedClient = LocationServices.getFusedLocationProviderClient(this)

        locationRequest = LocationRequest.create().apply {
            interval = 10_000   // 10秒更新一次
            fastestInterval = 5_000
            priority = Priority.PRIORITY_HIGH_ACCURACY
        }

        // 启动前台服务
        startForeground(1, buildNotification("初始化定位..."))
        startLocationUpdates()
    }

    private fun startLocationUpdates() {
        val callback = object : LocationCallback() {
            override fun onLocationResult(result: LocationResult) {
                val location = result.lastLocation
                location?.let {
                    val info = "纬度: ${it.latitude}, 经度: ${it.longitude}"
                    updateNotification(info)
                }
            }
        }

        // 注册位置监听
        fusedClient.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
    }

    private fun buildNotification(text: String): Notification {
        val channelId = "location_channel"
        val channelName = "定位服务"

        val manager = getSystemService(NotificationManager::class.java)
        val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW)
        manager.createNotificationChannel(channel)

        return NotificationCompat.Builder(this, channelId)
            .setContentTitle("定位服务运行中")
            .setContentText(text)
            .setSmallIcon(R.drawable.ic_location)
            .setOnlyAlertOnce(true)
            .build()
    }

    private fun updateNotification(text: String) {
        val notification = buildNotification(text)
        val manager = getSystemService(NotificationManager::class.java)
        manager.notify(1, notification)
    }

    override fun onBind(intent: Intent?): IBinder? = null
}

五、方法解读(仅功能说明)

  • requestLocationUpdates():开始监听位置变化

  • LocationCallback:位置变化后会回调此接口

  • buildNotification():构建通知对象,用于绑定前台服务

  • updateNotification():每次定位后更新通知栏内容

  • startForeground():正式启动前台服务,绑定通知栏

  • FusedLocationProviderClient:定位核心 API 客户端


六、项目总结与拓展

6.1 本项目达成效果

  • 实现了前后台稳定运行的 Android 定位服务

  • 兼容 Android 6 到 Android 14 系统

  • 定位精度高(FLP)、功耗低、响应快

  • 权限处理严谨、逻辑清晰、可移植性强

6.2 可拓展方向

  • 增加 后台定时上传位置信息 到服务器(可用 WorkManager)

  • 加入 轨迹记录与本地持久化(SQLite / Room)

  • 集成地图 SDK(如高德/百度)进行轨迹绘图

  • 增加电量优化功能,如静态区域时自动暂停定位

  • 使用前台通知按钮实现暂停/继续定位控制

6.3 注意事项

  • 国产系统兼容性:部分定制 ROM(如 MIUI)需手动设置自启/锁后台

  • 隐私声明合规:涉及位置获取必须展示权限用途、隐私说明

  • 高频定位风险:可能导致电池消耗快,应考虑场景优化策略


七、结语

通过本文,你已经系统掌握了 Android 定位功能的开发流程,从权限申请到高精度定位、从前台服务到通知栏展示,所有关键技术与代码细节都已覆盖,并以完整项目形式呈现。希望本文对你开发定位相关功能时能带来实质性帮助。

如需将该功能接入其他项目,可按模块化方式进行封装与拓展,并根据实际业务场景灵活配置参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值