Android LocationServices仅返回一次位置的问题求助
问题描述
实现一个位置日志记录器,要求在特定时间间隔(60秒)或位置移动至少50米时存储位置信息,但启动后仅能获取一次位置,修改模拟器位置后无响应。已授予ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION、WRITE_EXTERNAL_STORAGE权限,使用带Play Store的模拟器,测试过API 30-33版本,调整LocationRequest参数、替换Callback为监听器均无效。
问题代码
import android.annotation.SuppressLint; import android.location.Location; import android.os.Looper; import android.util.Log; import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.Granularity; import com.google.android.gms.location.LocationCallback; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationResult; import com.google.android.gms.location.LocationServices; import com.google.android.gms.location.Priority; import com.google.android.gms.tasks.OnCanceledListener; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; import de.remi.locker.database.entities.Trip; import de.remi.locker.util.MapsHelper; import de.remi.locker.util.PermissionHelper; public class AndroidLogger implements AutoLogger.ILoggerClient { private static final String TAG = "AndroidLogger"; private final FragmentActivity activity; private FusedLocationProviderClient client; private LocationCallback callBack; public AndroidLogger(FragmentActivity activity) { this.activity = activity; init(); } private void init() { client = LocationServices.getFusedLocationProviderClient(activity); callBack = new LocationCallback() { @Override public void onLocationResult(@NonNull LocationResult locationResult) { locationResult.getLocations().forEach(location -> handleLocation(location)); } }; } private void handleLocation(Location location) { Log.d(TAG, "handleLocation: " + location); } private LocationRequest getLocationRequest() { LocationRequest.Builder builder = new LocationRequest.Builder(10000); builder.setMinUpdateDistanceMeters(50); builder.setDurationMillis(60 * 1000); builder.setGranularity(Granularity.GRANULARITY_FINE); builder.setWaitForAccurateLocation(false); builder.setPriority(Priority.PRIORITY_HIGH_ACCURACY); return builder.build(); } @SuppressLint("MissingPermission") @Override public void startLogging(Trip trip) { if (!PermissionHelper.hasPermissions(activity.getApplicationContext(), MapsHelper.OSM_PERMISSIONS)) throw new UnsupportedOperationException("permissions missing "); client.requestLocationUpdates(getLocationRequest(), callBack, Looper.myLooper()).addOnCanceledListener(new OnCanceledListener() { @Override public void onCanceled() { Log.d(TAG, "onCanceled: "); } }).addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { Log.d(TAG, "onComplete: "); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "onFailure: ", e); } }).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void unused) { Log.d(TAG, "onSuccess: "); } }); } @Override public void stopLogging() { client.removeLocationUpdates(callBack); } }
排查与修复方案
1. 删除setDurationMillis配置
你的LocationRequest中调用了builder.setDurationMillis(60 * 1000),这个方法会限定位置更新的总时长,60秒后更新会自动停止,这是只能获取一次位置的核心原因。删除该配置,让更新持续运行直到手动调用stopLogging()。
2. 修正Looper参数
调用requestLocationUpdates时传入Looper.myLooper(),如果当前线程没有Looper(比如后台线程调用startLogging),会导致Callback无法接收回调。建议改为传入Looper.getMainLooper(),确保在主线程处理位置更新:
client.requestLocationUpdates(getLocationRequest(), callBack, Looper.getMainLooper())
3. 调整更新间隔参数
当前LocationRequest.Builder(10000)设置的是最快更新间隔10秒,但你预期的是60秒的常规间隔,应明确设置常规更新间隔,同时保留最快间隔避免频繁更新:
private LocationRequest getLocationRequest() { // 常规更新间隔60秒,最快10秒,移动50米触发更新 LocationRequest.Builder builder = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 60000); builder.setMinUpdateDistanceMeters(50); builder.setMinUpdateIntervalMillis(10000); builder.setGranularity(Granularity.GRANULARITY_FINE); builder.setWaitForAccurateLocation(false); return builder.build(); }
4. 模拟器位置模拟注意事项
- 开启模拟器开发者选项中的允许模拟位置权限;
- 模拟位置时确保移动距离超过50米,或等待60秒以上,触发对应的更新条件;
- 使用Android Studio的Extended Controls > Location功能,输入坐标后点击"Send"触发位置更新。
5. 补充Android 12+后台位置权限
Android 12(API 31)及以上版本,若App在后台需要记录位置,需额外申请ACCESS_BACKGROUND_LOCATION权限,并引导用户完成授权。
内容的提问来源于stack exchange,提问作者Michael Remme

