下面是一个完整的 Android 定位工具类实现,支持 GPS 和网络定位,兼容 Android 10 (API 29) 及以上版本的权限管理,并提供简洁的 API 供调用。
![图片[1]_Android 获取定位信息的工具类实现_知途无界](https://zhituwujie.com/wp-content/uploads/2025/11/d2b5ca33bd20251105102034.png)
一、工具类代码实现
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
/**
* 定位工具类 - 支持GPS和网络定位
* 注意:需要在AndroidManifest.xml中声明权限和meta-data
*/
public class LocationUtils {
private static final long MIN_TIME_MS = 1000 * 10; // 最小更新时间间隔(10秒)
private static final float MIN_DISTANCE_M = 10; // 最小更新距离(10米)
private Context mContext;
private LocationManager mLocationManager;
private LocationListener mLocationListener;
private LocationCallback mCallback;
public interface LocationCallback {
void onLocationSuccess(Location location); // 定位成功回调
void onLocationFailure(String error); // 定位失败回调
}
public LocationUtils(Context context) {
this.mContext = context.getApplicationContext();
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
/**
* 开始定位(异步获取一次位置)
* @param callback 定位结果回调
*/
public void requestLocation(@NonNull LocationCallback callback) {
this.mCallback = callback;
if (!checkLocationPermission()) {
if (mCallback != null) {
mCallback.onLocationFailure("缺少定位权限(需要ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION)");
}
return;
}
// 优先使用GPS定位
if (isGpsEnabled()) {
requestGpsLocation();
}
// 其次使用网络定位
else if (isNetworkEnabled()) {
requestNetworkLocation();
}
// 无可用定位方式
else {
if (mCallback != null) {
mCallback.onLocationFailure("无可用定位服务(GPS和网络均未开启)");
}
}
}
/**
* 检查是否已授予定位权限
*/
private boolean checkLocationPermission() {
return ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
/**
* 判断GPS是否开启
*/
private boolean isGpsEnabled() {
return mLocationManager != null && mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
/**
* 判断网络定位是否开启
*/
private boolean isNetworkEnabled() {
return mLocationManager != null && mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
/**
* 请求GPS定位
*/
private void requestGpsLocation() {
if (mLocationListener != null) {
mLocationManager.removeUpdates(mLocationListener);
}
mLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
stopLocationUpdates();
if (mCallback != null && location != null) {
mCallback.onLocationSuccess(location);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {
if (mCallback != null) {
mCallback.onLocationFailure("GPS定位已关闭");
}
}
};
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_MS,
MIN_DISTANCE_M,
mLocationListener
);
} catch (SecurityException e) {
if (mCallback != null) {
mCallback.onLocationFailure("GPS定位权限异常:" + e.getMessage());
}
}
}
/**
* 请求网络定位
*/
private void requestNetworkLocation() {
if (mLocationListener != null) {
mLocationManager.removeUpdates(mLocationListener);
}
mLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
stopLocationUpdates();
if (mCallback != null && location != null) {
mCallback.onLocationSuccess(location);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {
if (mCallback != null) {
mCallback.onLocationFailure("网络定位已关闭");
}
}
};
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_MS,
MIN_DISTANCE_M,
mLocationListener
);
} catch (SecurityException e) {
if (mCallback != null) {
mCallback.onLocationFailure("网络定位权限异常:" + e.getMessage());
}
}
}
/**
* 停止定位更新(防止内存泄漏)
*/
private void stopLocationUpdates() {
if (mLocationManager != null && mLocationListener != null) {
mLocationManager.removeUpdates(mLocationListener);
mLocationListener = null;
}
}
/**
* 释放资源(建议在Activity/Fragment销毁时调用)
*/
public void release() {
stopLocationUpdates();
mCallback = null;
}
}
二、AndroidManifest.xml 必要配置
在 AndroidManifest.xml 中添加以下内容:
<!-- 基础定位权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Android 10+ 需要声明前台服务类型(如果需要在后台定位) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- 如果使用Google Play服务的高精度定位,可添加(可选) -->
<!-- <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> -->
⚠️ 注意:
ACCESS_FINE_LOCATION:获取GPS高精度定位(包括经纬度、海拔、速度等)。ACCESS_COARSE_LOCATION:获取网络定位(精度较低,通常只能到城市级别)。- 从 Android 6.0 (API 23) 开始,定位权限属于危险权限,必须动态申请。
- **从 Android 10 (API 29) 开始,后台定位需要额外声明
ACCESS_BACKGROUND_LOCATION**(本工具类默认仅实现前台定位)。
三、动态权限申请(Activity/Fragment中调用)
在使用定位工具类前,必须确保已获取定位权限。以下是动态申请权限的示例代码(Kotlin/Java 均可):
1. 权限请求代码(Java 示例)
// 在Activity或Fragment中
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
private void checkAndRequestLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// 已有权限,直接调用定位
startLocation();
} else {
// 请求权限(兼容Android 11+的单次授权弹窗)
ActivityCompat.requestPermissions(
this,
new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},
LOCATION_PERMISSION_REQUEST_CODE
);
}
}
// 处理权限申请结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
boolean hasPermission = false;
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_GRANTED) {
hasPermission = true;
break;
}
}
if (hasPermission) {
startLocation(); // 用户同意,开始定位
} else {
Toast.makeText(this, "定位权限被拒绝,无法获取位置", Toast.LENGTH_SHORT).show();
}
}
}
// 实际调用定位工具类的方法
private void startLocation() {
LocationUtils locationUtils = new LocationUtils(this);
locationUtils.requestLocation(new LocationUtils.LocationCallback() {
@Override
public void onLocationSuccess(Location location) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
Log.d("LocationUtils", "定位成功: 纬度=" + latitude + ", 经度=" + longitude);
// TODO: 处理定位成功逻辑(如更新UI、上传服务器等)
}
@Override
public void onLocationFailure(String error) {
Log.e("LocationUtils", "定位失败: " + error);
Toast.makeText(MainActivity.this, "定位失败: " + error, Toast.LENGTH_SHORT).show();
}
});
}
2. 调用示例(在按钮点击或页面初始化时)
// 例如在Activity的onCreate中调用
checkAndRequestLocationPermission();
四、工具类特性说明
| 特性 | 说明 |
|---|---|
| 定位方式 | 优先使用GPS,失败后自动降级到网络定位 |
| 权限兼容 | 自动检查 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION |
| 异步回调 | 通过 LocationCallback 返回定位结果(成功/失败) |
| 资源释放 | 提供 release() 方法,防止内存泄漏 |
| 低功耗 | 设置最小更新时间(10秒)和距离(10米),避免频繁请求 |
| 错误处理 | 捕获权限异常、服务不可用等常见错误 |
五、注意事项
- Android 10+ 后台定位限制
如果需要在后台持续定位(如运动轨迹记录),需额外申请ACCESS_BACKGROUND_LOCATION权限,并声明前台服务(本工具类未包含,需自行扩展)。 - 高精度定位推荐
如需更高精度的定位(如导航、打车),建议集成 Google Play服务定位API 或 百度/高德地图SDK(提供更强大的定位能力和室内定位支持)。 - 模拟器测试
在Android Studio模拟器中测试时,可通过 Extended Controls → Location 手动设置经纬度模拟定位。 - 真机调试
真机需确保 GPS和网络功能正常,并在系统设置中开启定位服务。
通过以上工具类,你可以快速在Android应用中实现稳定、安全的定位功能,适用于天气、地图、本地生活等常见场景。如需进一步扩展(如持续定位、地理围栏等),可在此基础上继续完善。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容