我希望我的 Kotlin 应用程序仅在用户请求时获取当前准确的 (GPS) 位置一次。
到目前为止我一直在使用
fusedLocationClient.lastLocation
。这通常是成功的,但有时,即使 Google 地图和同一手机上运行的另一个应用程序具有准确的 GPS 位置,该应用程序也会返回一个遥远的位置(有时是一两英里)。
我尝试使用如何在 Kotlin 中使用“fusedLocationClient.getCurrentLocation”方法获取位置?中的代码来实现 getCurrentLocation 方法。但是,Android Studio 在
fusedLocationClient.getCurrentLocation(PRIORITY_HIGH_ACCURACY, object : CancellationToken()
报告错误
说我应该:
“重命名参考”
或
“为‘FusedLocationProviderClient.getCurrentLocation’创建扩展函数”
是否可以强制
lastLocation
方法使用GPS位置? (在清单中,我只包含了 ACCESS_FINE_LOCATION
权限,但这似乎不起作用。)
如果不行,谁能告诉我如何为
getCurrentLocation
方法创建扩展函数?我在网上没有找到任何例子。
编辑,按照 Gabe Sechan 的回答
虽然 Google Play 服务提供的 FusedLocation 通常被认为是 Google 更喜欢的,但不能依赖它来提供最准确的可用位置,正如 Gabe Sechan 在他的回答中评论的那样。
因此,出于我的目的,我转向了imthegaga在他在Android位置管理器,获取GPS位置的答案中提供的代码,如果没有GPS,则获取网络提供商位置 - 堆栈内存溢出。此代码使用 Android 位置类从 GPS 提供商(如果可用)和网络提供商(如果可用)获取最后的已知位置,如果两者都可用,则返回更准确的位置。
好吧,这里有一些令人困惑的概念。
1) 融合位置不是 GPS。可以是,但也可能不是。 Fused 是一种将 GPS(高功耗、慢锁定)与网络(低功耗、需要服务器协助)结合起来的尝试,以提供准确性和功耗的结合。如果你想要 GPS,你需要使用 Android 位置类,而不是 Google Play FusedLocation 东西(好处是即使你的设备上没有 Google Play,Android 东西也能工作)。
2)lastLocation 返回缓存的位置。它不会更新位置,也不会获取当前位置。它返回上次打开定位功能时的位置。它可能非常旧,或者如果没有缓存数据则可能为空。这是一种优化,仅当您知道自己在做什么并且不需要最新数据时才应使用。如果这样做,您需要使用 requestLocationUpdates,它实际上打开位置子系统并找到位置。
花了几个小时后,我解决了当前的位置问题。我已将代码分离到一个单独的类中。您可以使用以下课程来获取当前位置。
public class LocationTracker {
public static void getCurrentLocation(
@NonNull Context context,
OnLocationChangeListener onLocationChangeListener
) {
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
AtomicBoolean foundLocation = new AtomicBoolean(false);
Consumer<Location> locationConsumer = location -> {
if (!foundLocation.get()) {
foundLocation.set(true);
if (location != null) {
onLocationChangeListener.onComplete(getLatLng(location));
} else {
onLocationChangeListener.onComplete(new LatLng(0.0, 0.0));
}
}
};
registerLocationCallbackListener(locationManager, LocationManager.GPS_PROVIDER, locationConsumer);
registerLocationCallbackListener(locationManager, LocationManager.NETWORK_PROVIDER, locationConsumer);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
registerLocationCallbackListener(locationManager, LocationManager.FUSED_PROVIDER, locationConsumer);
}
}
private static void registerLocationCallbackListener(
LocationManager locationManager, String networkProvider, Consumer<Location> locationConsumer
) {
LocationManagerCompat.getCurrentLocation(locationManager, networkProvider,
new CancellationSignal(), Executors.newSingleThreadExecutor(), locationConsumer
);
}
@NonNull
private static LatLng getLatLng(@NonNull Location location) {
return new LatLng(location.getLatitude(), location.getLongitude());
}
public interface OnLocationChangeListener {
void onComplete(LatLng latLng);
}
}
用法
LocationTracker.getCurrentLocation(context, new OnLocationChangeListener() {
@Override
public void onComplete(LatLng latLng) {
}
}
);