Android Studio应用中位置信息返回null的原因排查
位置信息始终返回null但Activity Recognition正常的问题排查与解决
在Android Studio开发的应用中,我们实现了Activity Recognition与位置检测功能,发现latitude、longitude和speed始终返回null,但Activity Recognition功能可正常返回结果,且已在Manifest中配置所有相关权限。
相关代码
ActivityRecognitionService类
public class ActivityRecognitionService extends Service { //通知渠道常量 private static final int NOTIFICATION_ID = 1; private static final String CHANNEL_ID = "ActivityRecognitionChannel"; //位置识别相关变量 private String latitude; private String longitude; private String speed; LocationCallback mLocationCallback; @Override @SuppressLint("MissingPermission") public void onCreate() { super.onCreate(); LocationRequest mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(2000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { for (Location location : locationResult.getLocations()) { if (location != null) { latitude = String.valueOf(location.getLatitude()); longitude = String.valueOf(location.getLongitude()); speed = String.valueOf(location.getSpeed()); } else { Log.d("Location", "Location not available"); } } } }; LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(mLocationRequest, mLocationCallback, null); //创建通知渠道 NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Activity Recognition Channel", NotificationManager.IMPORTANCE_HIGH); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } //服务启动时调用,负责启动AR功能 @Override public int onStartCommand(Intent intent, int flags, int startId) { startForeground(NOTIFICATION_ID, createNotification()); new Thread( this::startActivityRecognition ).start(); return START_STICKY; } //服务销毁时执行 @Override public void onDestroy() { super.onDestroy(); stopActivityRecognition(); } //启动AR功能 @SuppressLint("MissingPermission") //权限已提前申请并校验 private void startActivityRecognition() { ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(this); Task<Void> task = activityRecognitionClient.requestActivityUpdates(2000, getActivityRecognitionPendingIntent()); task.addOnSuccessListener( success -> Log.d("ActivityRecognition", "Start activity recognition!") ); task.addOnFailureListener( error -> Log.e("ActivityRecognition", "Start activity recognition failed!") ); LocationServices.getFusedLocationProviderClient(this) .getLastLocation() .addOnSuccessListener(location -> { if(location != null){ latitude = String.valueOf(location.getLatitude()); longitude = String.valueOf(location.getLongitude()); speed = String.valueOf(location.getSpeed()); } else { Log.d("Location", "Location not available"); } }); } //停止AR功能 @SuppressLint("MissingPermission") //权限已提前申请并校验 private void stopActivityRecognition() { LocationServices.getFusedLocationProviderClient(this).removeLocationUpdates(mLocationCallback); ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(this); Task<Void> task = activityRecognitionClient.removeActivityUpdates(getActivityRecognitionPendingIntent()); task.addOnSuccessListener( success -> Log.d("ActivityRecognition", "Stop activity recognition!") ); task.addOnFailureListener( error -> Log.e("ActivityRecognition", "Stop activity recognition failed!") ); } //为ActivityRecognition传递Intent @SuppressLint("MissingPermission") private PendingIntent getActivityRecognitionPendingIntent() { Intent intent = new Intent(this, ActivityTransitionsReceiver.class); intent.putExtra("Latitude", latitude); intent.putExtra("Longitude", longitude); intent.putExtra("Speed", speed); return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_MUTABLE); } //创建并显示状态栏通知 @SuppressLint("MissingPermission") //权限已提前申请并校验 private Notification createNotification() { Intent notificationIntent = new Intent(this, HomeActivity.class); notificationIntent.setAction(Intent.ACTION_MAIN); notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Activity Recognition Service") .setContentText("Running...") .setContentIntent(pendingIntent) .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(false) .setOngoing(true) .build(); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(NOTIFICATION_ID, notification); return notification; } @Override public IBinder onBind(Intent intent) { return null; } }
ActivityTransitionsReceiver类
public class ActivityTransitionsReceiver extends IntentService { public ActivityTransitionsReceiver() { super("ActivityRecognitionService"); } //接收包含识别到的活动的Intent @Override protected void onHandleIntent(Intent intent) { if (intent != null) { String latitude = intent.getStringExtra("Latitude"); String longitude = intent.getStringExtra("Longitude"); String speed = intent.getStringExtra("Speed"); if (ActivityRecognitionResult.hasResult(intent)) { ActivityRecognitionResult activityResult = ActivityRecognitionResult.extractResult(intent); if (activityResult != null) { handleActivityRecognitionResult(activityResult, latitude, longitude, speed); } } } } //处理识别到的活动 @SuppressLint("MissingPermission") //权限已提前申请并校验 private void handleActivityRecognitionResult(ActivityRecognitionResult activityResult, String latitude, String longitude, String speed) { DetectedActivity mostProbableActivity = activityResult.getMostProbableActivity(); int confidence = mostProbableActivity.getConfidence(); int activityType = mostProbableActivity.getType(); Log.i("AR", "Activity detected: " + getActivityName(activityType) + "/" + confidence + "\nLatitude: " + latitude + "\nLongitude: " + longitude + "\nSpeed: " + speed); } //获取识别到的活动名称 private String getActivityName(int activityType) { switch (activityType) { case DetectedActivity.IN_VEHICLE: return "In vehicle"; case DetectedActivity.ON_BICYCLE: return "On bicycle"; case DetectedActivity.ON_FOOT: return "On foot"; case DetectedActivity.RUNNING: return "Running"; case DetectedActivity.STILL: return "Still"; case DetectedActivity.TILTING: return "Tilting"; case DetectedActivity.WALKING: return "Walking"; case DetectedActivity.UNKNOWN: return "Unknown"; default: return "Undefined"; } } }
问题原因分析
- PendingIntent初始化时机错误:
getActivityRecognitionPendingIntent()在启动Activity Recognition时被调用,此时位置信息还未获取到(getLastLocation()或LocationCallback的回调可能还未执行),导致Intent的Extra参数都是初始null值。且PendingIntent一旦创建,若不主动更新,内部的Extra不会自动同步后续的变量变化。 - 位置更新与数据传递不同步:
LocationCallback中更新了latitude等变量,但这些变量不会自动同步到已创建的PendingIntent中,Activity Recognition触发时传递的仍是最初的null值。 getLastLocation()的不确定性:该方法返回设备最后一次缓存的位置,若设备长时间未获取位置或缓存失效,会返回null,无法依赖它作为唯一位置来源。
解决方案
方案一:位置更新时重新创建PendingIntent
每次LocationCallback获取到新位置后,重新注册Activity Recognition,用更新后的位置信息创建新的PendingIntent替换旧的:
修改onLocationResult方法:
@Override public void onLocationResult(LocationResult locationResult) { for (Location location : locationResult.getLocations()) { if (location != null) { latitude = String.valueOf(location.getLatitude()); longitude = String.valueOf(location.getLongitude()); speed = String.valueOf(location.getSpeed()); // 位置更新后,重新注册Activity Recognition以更新PendingIntent updateActivityRecognitionPendingIntent(); } else { Log.d("Location", "Location not available"); } } }
添加updateActivityRecognitionPendingIntent方法:
@SuppressLint("MissingPermission") private void updateActivityRecognitionPendingIntent() { ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(this); // 先移除旧的PendingIntent activityRecognitionClient.removeActivityUpdates(getActivityRecognitionPendingIntent()) .addOnSuccessListener(unused -> { // 注册新的PendingIntent,此时位置信息已更新 activityRecognitionClient.requestActivityUpdates(2000, getActivityRecognitionPendingIntent()) .addOnSuccessListener(success -> Log.d("ActivityRecognition", "Updated activity recognition pending intent!")) .addOnFailureListener(error -> Log.e("ActivityRecognition", "Failed to update activity recognition pending intent!")); }) .addOnFailureListener(error -> Log.e("ActivityRecognition", "Failed to remove old activity updates!")); }
方案二:在Receiver中实时获取位置
不在PendingIntent中传递位置信息,而是在Activity识别触发时直接调用FusedLocationProvider获取最新位置,保证每次拿到的都是当前最新数据:
修改ActivityTransitionsReceiver的handleActivityRecognitionResult方法:
@SuppressLint("MissingPermission") private void handleActivityRecognitionResult(ActivityRecognitionResult activityResult) { DetectedActivity mostProbableActivity = activityResult.getMostProbableActivity(); int confidence = mostProbableActivity.getConfidence(); int activityType = mostProbableActivity.getType(); // 实时获取最新位置 LocationServices.getFusedLocationProviderClient(this) .getLastLocation() .addOnSuccessListener(location -> { String latitude = null; String longitude = null; String speed = null; if (location != null) { latitude = String.valueOf(location.getLatitude()); longitude = String.valueOf(location.getLongitude()); speed = String.valueOf(location.getSpeed()); } else { Log.d("Location", "Location not available"); } Log.i("AR", "Activity detected: " + getActivityName(activityType) + "/" + confidence + "\nLatitude: " + latitude + "\nLongitude: " + longitude + "\nSpeed: " + speed); }) .addOnFailureListener(e -> Log.e("Location", "Failed to get location", e)); }
修改onHandleIntent方法,不再传递位置参数:
@Override protected void onHandleIntent(Intent intent) { if (intent != null) { if (ActivityRecognitionResult.hasResult(intent)) { ActivityRecognitionResult activityResult = ActivityRecognitionResult.extractResult(intent); if (activityResult != null) { handleActivityRecognitionResult(activityResult); } } } }
简化getActivityRecognitionPendingIntent方法:
private PendingIntent getActivityRecognitionPendingIntent() { Intent intent = new Intent(this, ActivityTransitionsReceiver.class); return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_MUTABLE); }
额外优化建议
- 确认运行时权限:Android 6.0+需动态申请
ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION(位置权限)和ACTIVITY_RECOGNITION(Activity识别权限),确保用户已授权。 - 调整LocationRequest参数:
setInterval(2000)间隔过短会增加耗电,建议根据需求调整为5000ms或更长。 - 监听位置可用性:在
LocationCallback中重写onLocationAvailability方法,处理位置不可用的场景。
内容的提问来源于stack exchange,提问作者Acco
相关产品推荐
相关产品推荐

