小编典典

Android:LocationManager 与 Google Play 服务

all

我想构建一个以获取用户当前位置为中心的应用程序,然后通过Google Places API 找到他/她附近的兴趣点(如酒吧、餐馆等)。

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

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

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


阅读 164

收藏
2022-08-27

共1个答案

小编典典

Android上的用户位置

在 Android 上获取用户的位置比在 iOS 上要简单一些。要开始混淆,有两种完全不同的方法可以做到这一点。第一个是使用 Android APIs
android.location.LocationListener,第二个是使用 Google Play Services APIs
com.google.android.gms.location.LocationListener。让我们通过他们两个。

  1. Android的Location API

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

* `LocationManager.GPS_PROVIDER`——该提供商使用卫星确定位置。根据条件,此提供程序可能需要一段时间才能返回位置修复。
* `LocationManager.NETWORK_PROVIDER`' 该提供商根据手机信号塔和 WiFi 接入点的可用性确定位置。通过网络查找检索结果。
* `LocationManager.PASSIVE_PROVIDER`——此提供者将返回其他提供者生成的位置。当其他应用程序或服务请求位置更新时,您会被动地接收位置更新,而您自己却没有实际请求位置。

它的要点是你LocationManager从系统中获取一个对象,实现LocationListener,然后requestLocationUpdatesLocationManager.

这是一个代码片段:

    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
指南

很好地解释了代码。但他们也提到,在大多数情况下,通过使用Google 定位服务
API
,您将获得更好的电池性能以及更合适的准确度。现在混乱开始了!

  1. Google 的定位服务 API

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

要使用 Google 的定位服务,您的应用需要连接到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
仅在至少有一个客户端连接到它时才会维护后台位置。一旦第一个客户端连接,它将立即尝试获取位置。如果您的活动是第一个连接的客户端并且您立即调用getLastLocation()onConnected()则可能没有足够的时间让第一个位置进入。这将location导致null.

要解决此问题,您必须(不确定地)等待提供商获取位置然后调用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 服务客户端的情况下请求位置。

  • 用户已禁用定位服务

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

如果您的应用要求他们启用定位服务,您可能需要显示一条消息或祝酒词。遗憾的是,无法检查用户是否在 Google 的位置服务 API
中禁用了位置服务。为此,您将不得不求助于 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;

并在您的方法中使用该locationEnabled标志,如下所示:onConnected

    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

2022-08-27