- 核心概念:GPS vs. 网络定位
- Android 定位系统架构:Fused Location Provider
- 实现定位的步骤(以现代 API 为准)
- 关键代码示例
- 最佳实践与注意事项
- 如何选择定位方式?
核心概念:GPS vs. 网络定位
要明白 GPS 和网络定位是两种完全不同的技术,它们各有优缺点。

| 特性 | GPS (Global Positioning System) | 网络定位 |
|---|---|---|
| 技术原理 | 通过手机接收多颗 GPS 卫星发射的信号,通过三角计算法精确确定设备的经纬度、海拔等信息。 | 通过连接的 Wi-Fi 或移动网络基站来估算位置。 |
| 精度 | 高,室外开阔地带可达 5 - 10 米,甚至更高。 | 较低,Wi-Fi 定位精度在几十米到几百米;基站定位精度在几百米到几公里。 |
| 首次定位时间 | 慢 (TTFF - Time to First Fix),冷启动可能需要几十秒甚至几分钟,因为需要下载卫星星历数据。 | 快,几乎是即时的,因为它只需要查询网络信息。 |
| 耗电量 | 高,持续开启 GPS 模块会显著消耗电量。 | 低,查询网络信息耗电量相对较小。 |
| 使用环境 | 依赖天空,在室内、隧道、高楼林立的“城市峡谷”中,信号会变弱或完全丢失。 | 依赖网络,只要有手机信号(2G/3G/4G/5G)或 Wi-Fi,就可以定位。 |
| 数据费用 | 免费,接收卫星信号不产生费用。 | 可能产生费用,查询基站信息需要与运营商通信,但通常流量很小。 |
Android 定位系统架构:Fused Location Provider
在 Android 6.0 (API 23) 及更高版本中,Google 推荐使用 Fused Location Provider,它不是一个简单的 GPS 或网络定位,而是一个智能的、统一的定位服务。
Fused Location Provider (FLP) 的核心思想是:
- 智能融合:它会根据你的应用请求的精度、设备当前的状态(如是否插电、网络状况、已知的辅助数据等),自动在 GPS、Wi-Fi、蓝牙、基站等多种定位方式之间做出最优选择。
- 降低功耗:通过智能调度,它可以在保证精度的前提下,最大限度地降低定位对电量的消耗。
- 简化开发:开发者不再需要手动切换或组合不同的定位提供者(
GPS_PROVIDER,NETWORK_PROVIDER),只需告诉系统你想要的精度级别,系统会搞定一切。
在现代 Android 开发中,你应该始终优先使用 Fused Location Provider。
实现定位的步骤(以现代 API 为准)
下面是实现定位功能的完整流程,我们将使用 Fused Location Provider。

步骤 1:添加权限
在 AndroidManifest.xml 中必须声明以下权限:
<!-- 用于访问网络,网络定位需要此权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 用于访问 GPS,GPS 定位需要此权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 用于访问网络(Wi-Fi 或基站)进行定位,精度较低 --> <!-- 如果只申请 ACCESS_FINE_LOCATION,则此权限会被隐式包含,但最好显式声明 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 从 Android 10 (API 29) 开始,在后台获取位置需要此权限 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
步骤 2:动态请求权限(Android 6.0+)
在运行时,特别是针对 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION,必须向用户请求授权。
// 在 Activity 或 Fragment 中
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 权限尚未授予,请求权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
// 权限已授予,可以开始定位
startLocationUpdates();
}
步骤 3:创建 LocationCallback 和 LocationRequest
LocationCallback 是一个抽象类,用于接收位置更新,你需要实现它的 onLocationResult 方法。
LocationRequest 用于告诉 FLP 你对定位更新的要求,

setPriority: 定位精度优先级。PRIORITY_HIGH_ACCURACY: 最高精度,优先使用 GPS。PRIORITY_BALANCED_POWER_ACCURACY: 平衡精度和功耗,优先使用网络定位。PRIORITY_LOW_POWER: 低功耗,只使用网络定位。PRIORITY_NO_POWER: 不耗电,只在其他应用请求位置时顺便获取。
setInterval: 请求位置更新的最小间隔时间(毫秒),注意,这只是一个请求,系统可能会根据优化策略返回更频繁或更少的数据。setFastestInterval: 应用能处理位置更新的最快间隔时间,这有助于防止 UI 线程阻塞。
private LocationCallback locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
// 获取最新的位置信息
Location location = locationResult.getLastLocation();
// 在这里更新 UI 或处理位置数据
updateUI(location);
}
};
private LocationRequest locationRequest;
private void createLocationRequest() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(10000); // 10秒
locationRequest.setFastestInterval(5000); // 5秒
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // 高精度
}
步骤 4:获取 FusedLocationProviderClient
这是与 FLP 交互的入口点。
private FusedLocationProviderClient fusedLocationClient; // 在 onCreate 或类似的生命周期方法中 fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
步骤 5:开始和停止位置更新
开始更新:
private void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 权限检查
return;
}
createLocationRequest();
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
}
停止更新:
当你的应用不再需要位置信息时(Activity 暂停或销毁时),必须停止位置更新,否则会持续消耗电量。
private void stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback);
}
步骤 6:在生命周期中管理定位
最佳实践是在 onStart() 中开始定位,在 onStop() 中停止定位。
@Override
protected void onStart() {
super.onStart();
if (checkPermissions()) {
startLocationUpdates();
}
}
@Override
protected void onStop() {
super.onStop();
stopLocationUpdates();
}
关键代码示例(一个完整 Activity)
public class MainActivity extends AppCompatActivity {
private FusedLocationProviderClient fusedLocationClient;
private LocationCallback locationCallback;
private TextView locationTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationTextView = findViewById(R.id.locationTextView);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
// 创建 LocationCallback
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
Location location = locationResult.getLastLocation();
String text = "纬度: " + location.getLatitude() + "\n" +
"经度: " + location.getLongitude() + "\n" +
"精度: " + location.getAccuracy() + " 米";
locationTextView.setText(text);
}
};
// 检查并请求权限
if (!checkPermissions()) {
requestPermissions();
}
}
private boolean checkPermissions() {
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
1);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grant 