1. 完整的LocationUtils工具类实现
import android.Manifest;
import android.app.Activity;
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 android.os.Looper;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class LocationUtils {
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
private static LocationManager locationManager;
private static LocationListener locationListener;
// 回调接口
public interface LocationCallback {
void onLocationResult(Location location);
void onPermissionDenied();
void onLocationError(String error);
}
/**
* 检查并获取当前位置
* @param activity 当前Activity
* @param callback 位置回调
* @param requireFineLocation 是否需要高精度定位
*/
public static void getCurrentLocation(Activity activity, LocationCallback callback, boolean requireFineLocation) {
String permission = requireFineLocation ?
Manifest.permission.ACCESS_FINE_LOCATION :
Manifest.permission.ACCESS_COARSE_LOCATION;
if (checkPermission(activity, permission)) {
startLocationUpdates(activity, callback, requireFineLocation);
} else {
requestLocationPermission(activity, callback, requireFineLocation);
}
}
/**
* 检查权限是否已授予
*/
private static boolean checkPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED;
}
/**
* 请求定位权限
*/
private static void requestLocationPermission(Activity activity,
final LocationCallback callback, final boolean requireFineLocation) {
String permission = requireFineLocation ?
Manifest.permission.ACCESS_FINE_LOCATION :
Manifest.permission.ACCESS_COARSE_LOCATION;
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
// 解释为什么需要权限
callback.onLocationError("需要位置权限才能获取当前位置");
}
ActivityCompat.requestPermissions(activity,
new String[]{permission},
LOCATION_PERMISSION_REQUEST_CODE);
}
/**
* 处理权限请求结果
* 需要在Activity的onRequestPermissionsResult中调用
*/
public static void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults,
Activity activity, LocationCallback callback,
boolean requireFineLocation) {
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startLocationUpdates(activity, callback, requireFineLocation);
} else {
callback.onPermissionDenied();
}
}
}
/**
* 开始获取位置更新
*/
private static void startLocationUpdates(Activity activity,
final LocationCallback callback, boolean requireFineLocation) {
locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null) {
callback.onLocationError("无法获取位置服务");
return;
}
// 检查GPS和网络是否可用
boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGpsEnabled && !isNetworkEnabled) {
callback.onLocationError("请打开位置服务");
return;
}
String provider = requireFineLocation ?
LocationManager.GPS_PROVIDER :
LocationManager.NETWORK_PROVIDER;
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
// 获取到位置后停止更新并返回结果
stopLocationUpdates();
callback.onLocationResult(location);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {
callback.onLocationError("位置服务被禁用");
}
};
try {
if (ActivityCompat.checkSelfPermission(activity,
requireFineLocation ?
Manifest.permission.ACCESS_FINE_LOCATION :
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
// 请求位置更新
locationManager.requestSingleUpdate(provider, locationListener, Looper.getMainLooper());
// 同时获取最后一次已知位置
Location lastKnownLocation = locationManager.getLastKnownLocation(provider);
if (lastKnownLocation != null) {
callback.onLocationResult(lastKnownLocation);
}
} catch (SecurityException e) {
callback.onLocationError("位置权限异常: " + e.getMessage());
} catch (IllegalArgumentException e) {
callback.onLocationError("位置提供者不可用: " + e.getMessage());
}
}
/**
* 停止位置更新
*/
public static void stopLocationUpdates() {
if (locationManager != null && locationListener != null) {
locationManager.removeUpdates(locationListener);
}
}
}
2. 使用示例
在Activity中使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGetLocation = findViewById(R.id.btn_get_location);
btnGetLocation.setOnClickListener(v -> {
// 获取高精度位置
LocationUtils.getCurrentLocation(this, new LocationUtils.LocationCallback() {
@Override
public void onLocationResult(Location location) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
// 处理位置信息
Log.d("Location", "Lat: " + latitude + ", Lng: " + longitude);
}
@Override
public void onPermissionDenied() {
// 处理权限被拒绝
Toast.makeText(MainActivity.this,
"需要位置权限才能使用此功能",
Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationError(String error) {
// 处理位置错误
Toast.makeText(MainActivity.this, error, Toast.LENGTH_SHORT).show();
}
}, true); // true表示需要高精度定位
});
}
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 将权限结果转发给工具类处理
LocationUtils.onRequestPermissionsResult(
requestCode, permissions, grantResults,
this, new LocationUtils.LocationCallback() {
@Override
public void onLocationResult(Location location) {
// 处理位置信息
}
@Override
public void onPermissionDenied() {
// 处理权限被拒绝
}
@Override
public void onLocationError(String error) {
// 处理错误
}
}, true);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 停止位置更新
LocationUtils.stopLocationUpdates();
}
}
3. 工具类功能说明
权限管理:
- 自动检查定位权限
- 动态请求缺少的权限
- 处理权限请求结果
位置获取:
- 支持高精度(GPS)和低精度(网络)定位
- 获取单次位置更新
- 获取最后一次已知位置作为快速响应
错误处理:
- 权限被拒绝
- 位置服务不可用
- 其他位置获取错误
资源管理:
- 提供停止位置更新的方法
- 避免内存泄漏
4. 高级功能扩展
如果需要更高级的功能,可以考虑添加以下内容:
- 超时处理:
// 添加超时Handler
private static final int LOCATION_TIMEOUT_MS = 30000; // 30秒超时
private static Handler timeoutHandler = new Handler();
private static void startLocationUpdatesWithTimeout(...) {
// 设置超时任务
timeoutHandler.postDelayed(() -> {
stopLocationUpdates();
callback.onLocationError("获取位置超时");
}, LOCATION_TIMEOUT_MS);
startLocationUpdates(...);
}
// 在获取到位置后取消超时任务
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
timeoutHandler.removeCallbacksAndMessages(null);
// ...原有逻辑
}
};
- 后台定位支持:
// 在AndroidManifest.xml中添加
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
// 在工具类中检查Android 10+的后台权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 请求后台权限
}
}
- 位置缓存:
// 添加静态变量缓存位置
private static Location lastLocation;
private static long lastLocationTime;
public static Location getCachedLocation() {
// 如果缓存的位置在有效期内(如5分钟内)则返回
if (lastLocation != null &&
System.currentTimeMillis() - lastLocationTime < 300000) {
return lastLocation;
}
return null;
}