Android: LocationManager vs Google Play Services

我想建立一个应用程序,围绕获取用户的当前位置,然后找到兴趣点(如酒吧,餐馆等) ,靠近他/她通过 Google Places API

在网上搜索一个地方开始,我遇到了一些教程,使用 LocationManager类和其他一些使用 Google Play 服务,以找到用户的位置。

乍一看,他们都做同样的事情,但是因为我是新手,我有点困惑,我不知道哪种方法最适合我的需要。所以,我想问你:

这两种查找位置的方法有什么不同(如果有的话) ?

75105 次浏览

你应该使用 Google Play Services 的地址 api 而不是 LocationManager:

GooglePlay 服务位置 API 比 Android 更受欢迎 框架位置 API (android.location)作为添加位置的方式 如果你正在使用 Android 系统 框架位置 API,强烈建议您切换到 尽快使用 GooglePlay 服务位置 API。

至于为什么要改变,谷歌表示:

Google 位置服务 API,Google Play 服务的一部分, 提供了一个更强大的高级框架,可以自动 处理位置提供程序、用户移动和位置准确性 还处理基于功耗的位置更新调度 你提供的参数。在大多数情况下,你会得到更好的电池 性能,以及更适当的准确性,通过使用 位置服务 API。

Android 上的用户位置

在 Android 上获取用户的位置不像在 iOS 上那么简单。要引起混淆,有两种完全不同的方法可以做到。第一个是使用来自 android.location.LocationListener的 Android API,第二个是使用 GooglePlayServicesAPI com.google.android.gms.location.LocationListener。我们把他们两个都查一遍。

  1. Android 的位置 API

    Android 的位置 API 使用三个不同的提供者来获取位置-

    • LocationManager.GPS_PROVIDERー此供应商使用卫星确定位置。根据条件,此提供程序可能需要一段时间才能返回位置修复程序。
    • LocationManager.NETWORK_PROVIDERー此供应商根据手机基站和 WiFi 接入点的可用性确定位置。通过网络查找检索结果。
    • LocationManager.PASSIVE_PROVIDERー此提供程序将返回其他提供程序生成的位置。当其他应用程序或服务请求位置更新时,您将被动地接收位置更新,而不必亲自请求位置更新。

其要点是从系统中获取 LocationManager对象,实现 LocationListener,并在 LocationManager上调用 requestLocationUpdates

下面是一段代码:

    LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}


public void onStatusChanged(String provider, int status, Bundle extras) {}


public void onProviderEnabled(String provider) {}


public void onProviderDisabled(String provider) {}
};


// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

Google 的定位策略 API 指南 很好地解释了这段代码。但他们也提到,在大多数情况下,您将得到更好的电池性能,以及更适当的准确性,使用 谷歌位置服务 API而不是。现在混乱开始了!

  1. Google 的位置服务 API

Google 的位置服务 API 是 Google Play Services APK (这里是如何设置它)的一部分。它们是基于 Android 的 API 构建的。这些 API 提供了一个“融合位置提供程序”,而不是上面提到的提供程序。此提供程序根据准确性、电池使用情况等自动选择要使用的底层提供程序。它之所以快,是因为您从不断更新它的系统范围的服务获取位置信息。你可以使用更高级的功能,如地理围栏。

要使用谷歌的定位服务,你的应用程序需要连接到 GooglePlayServicesClient。要连接到客户机,您的活动(或片段,或者其他)需要实现 GooglePlayServicesClient.ConnectionCallbacksGooglePlayServicesClient.OnConnectionFailedListener接口。 下面是一个示例代码:

    public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {
LocationClient locationClient;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
locationClient = new LocationClient(this, this, this);
}


@Override
public void onConnected(Bundle bundle) {
Location location = locationClient.getLastLocation() ;
Toast.makeText(this, "Connected to Google Play Services", Toast.LENGTH_SHORT).show();
}


@Override
public void onDisconnected() {
Toast.makeText(this, "Connected from Google Play Services.", Toast.LENGTH_SHORT).show();
}


@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// code to handle failed connection
// this code can be found here — http://developer.android.com/training/location/retrieve-current.html
}
  • 为什么 locationClient.getLastLocation()是无效的?

locationClient.getLastLocation()从客户端获取最后一个已知位置。但是,如果至少有一个客户端连接到该服务器,则 Fused Location Provider 将只维护后台位置。一旦第一个客户端连接上,它将立即尝试获取一个位置。如果您的活动是第一个连接的客户端,并且您立即在 onConnected()中调用 getLastLocation(),那么可能没有足够的时间来访问第一个位置。这将导致 locationnull

要解决这个问题,您必须等待(不确定地) ,直到提供者获得位置,然后调用 getLastLocation(),这是不可能知道的。另一个(更好的)选择是实现 com.google.android.gms.location.LocationListener接口以接收定期的位置更新(并在获得第一次更新时关闭它)。

    public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
// . . . . . . . . more stuff here
LocationRequest locationRequest;
LocationClient locationClient;


@Override
protected void onCreate(Bundle savedInstanceState) {
// . . . . other initialization code
locationClient = new LocationClient(this, this, this);
locationRequest = new LocationRequest();
// Use high accuracy
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
locationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
locationRequest.setFastestInterval(FASTEST_INTERVAL);
}
// . . . . . . . . other methods
@Override
public void onConnected(Bundle bundle) {
Location location = locationClient.getLastLocation();
if (location == null)
locationClient.requestLocationUpdates(locationRequest, this);
else
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
// . . . . . . . . other methods
@Override
public void onLocationChanged(Location location) {
locationClient.removeLocationUpdates(this);
// Use the location here!!!
}

在这段代码中,您将检查客户端是否已经拥有最后一个位置(在 onConnected中)。如果没有,那么请求位置更新,并在获得更新后立即关闭请求(在 onLocationChanged()回调中)。

请注意,locationClient.requestLocationUpdates(locationRequest, this);必须位于 onConnected回调函数内部,否则您将得到 IllegalStateException,因为您将尝试请求未连接到 Google Play Services Client 的位置。

  • 用户已禁用位置服务

很多时候,用户会禁用位置服务(为了节省电池或隐私)。在这种情况下,上面的代码仍然会请求位置更新,但是 onLocationChanged将永远不会被调用。您可以通过检查用户是否已禁用位置服务来停止请求。

如果你的应用程序需要他们启用定位服务,你会想要显示一条消息或祝酒词。不幸的是,没有办法检查用户是否在 Google 的 LocationServicesAPI 中禁用了定位服务。为此,你将不得不求助于 Android 的 API。

在你的 onCreate方法中:

    LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationEnabled = false;
Toast.makeText(getActivity(), "Enable location services for accurate data", Toast.LENGTH_SHORT).show();
}
else locationEnabled = true;

onConnected方法中使用 locationEnabled标志,如下所示:

    if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
locationClient.requestLocationUpdates(locationRequest, this);
}

更新

文档被更新,LocationClient 被删除,API 支持从对话框中一键启用 GPS:

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
});


task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});

连结 https://developer.android.com/training/location/change-location-settings#prompt

新的位置客户端: FusedLocationProviderClient

  private FusedLocationProviderClient fusedLocationClient;


@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}

在执行任何定位任务之前,建议先执行 https://developer.android.com/training/location

根据我的经验,“更准确”并不意味着用任何方式更好。除非我遗漏了什么,如果你想确保 GPS 被使用,位置管理器是唯一的方法去。我们用我们的应用程序来跟踪车辆,同样,除非我遗漏了什么,谷歌播放服务经常提供一些非常不准确的位置。

Google Location Services API 是 Google Play Services 的一部分,它提供了一个更强大的高级框架,可以自动处理 位置供应商用户移动定位精度定位精度。它还根据您提供的功耗参数处理位置更新调度。在大多数情况下,您将通过使用 LocationServicesAPI 获得 更好的电池性能以及更合适的准确性。

更详细的差异之间的两个 apis 谷歌播放服务位置 APIAndroid 框架位置 API可以找到 给你

我使用 Google 位置服务 API 已经有一段时间了。它确实有优点,因为它封装了用于确定位置的多个源的复杂性。但是它 包裹得太严重了,所以当你得到一个奇怪的位置,你没有办法确定那个奇怪的位置来自哪里。

在现实生活中,我有几个反常的价值观弹出,是10公里远的实际位置。唯一的解释是,这些疯狂的位置源于谷歌 Wi-Fi 或 NWK 数据库中的错误——这些错误将永远存在,因为 Wi-Fi 和网络拓扑每天都在变化。但不幸的是(令人惊讶的是) ,API 没有提供任何关于如何导出个别位置的信息。

enter image description here

这给你留下了问题,必须过滤掉畸形值的基础上,合理性检查的速度,加速度,轴承等。

或者回到原来的框架 API 只使用 GPS 我决定在 Google 改进融合 API 之前这么做。

是的,谷歌播放服务位置服务 API 可以提供非常具有误导性的位置信息。WiFi 调制解调器被移动,WiFi 调制解调器用不正确的位置信息进行更新(例如,如果位置被更新 WiFi 调制解调器位置的 Android 设备欺骗) ,还有许多其他情况可能导致来自 WiFi 调制解调器三角定位的不正确的位置数据。在我们所有的应用程序中,精确的位置是强制性的,我们只使用 GPS。

Google Play Service Location API 和基于 GPS 服务的 Android Framework Location API 的区别

FusedLocationProviderClient

  1. 对于第一次获取,位置不能为 null (即: 其他应用程序需要更新 GoogleplayService 数据库中的 Lastknown 位置。如果为空,则需要修改)
  2. 对于下一个顺序获取,它使用 requestLocationUpdates()方法来获取位置。
  3. 位置获取仅基于 locationRequest.setInterval(milliseconds)setFastestInterval(milliseconds),而不基于 用户位置改变
  4. 返回的 LatLng 值包含 只有7个小数值(例如: 11.9557996,79.8234599)、 没那么准确
  5. 建议,当您的应用程序需求采取当前位置 距离可以忽略不计(50-100米精度)
  6. 有效使用电池。

地点经理阿皮

  1. 使用 locationManager.requestLocationUpdate ()调用用户位置获取
  2. 基于用户 位置改变时间间隔 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, milliseconds, mindistance, Mylocationlistener)的位置获取

  3. 返回的 LatLng 值包含 14个小数值 (例如: 11.9457459496334279.81166719458997) 精确的位置值

  4. 推荐 用于基于位置的应用程序,当需要更精确的时候,甚至是米。
  5. 电池使用量基于 提取间隔和提取距离。

Android 位置

LocationManager -Context.getSystemService(Context.LOCATION_SERVICE)

  • ACCESS _ COARSE _ LOCATION-提供不太准确的位置(城市街区) ,但更快,不会消耗太多电池

    • NETWORK _ PROVIDER-使用信号塔,wifi 接入点
    • PASSIVE _ PROVIDER-当系统中的其他人使用其他提供程序时,订阅位置更新
  • ACCESS _ FINE _ LOCATION-提供更好和准确的位置(最多几米)。使用与 ACCESS _ COARSE _ LOCATION 相同的提供程序

    • 使用 GPS _ PROVIDER- 卫星

基于 Google Play 服务的 Google API 定位服务 -GoogleApiClient。具有访问通过系统的位置事件的高级 API。它有更好的电池性能,但不能安装在一些设备

  • 融合位置提供程序-自动选择一个适当的提供程序基于您的需求和设备条件

当通过谷歌提供的 AlertDialog解决方案启用 GPS 时,增加了公认的答案。ActivityResultContract的实施情况如下:

// Global Activity Scope


ActivityResultLauncher<IntentSenderRequest> gpsRequestLauncher = registerForActivityResult(
new ActivityResultContracts.StartIntentSenderForResult(), callback -> {
if(callback.getResultCode() == RESULT_CANCELED) {
// Request Cancelled
} else {
//  GPS Enabled
}
});

因为文档中的代码已经过时,onActivityResults已经过时

task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
IntentSenderRequest request = new IntentSenderRequest.Builder(
e.resolution).build();
gpsRequestLauncher.launch(request);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});