我想构建一个以获取用户当前位置为中心的应用程序,然后通过Google Places API 找到他/她附近的兴趣点(如酒吧、餐馆等)。
在网上搜索一个开始的地方时,我遇到了一些使用LocationManager该类的教程和一些使用 Google Play 服务 来查找用户位置的教程。
LocationManager
乍一看,他们俩都做同样的事情,但由于我是新手,所以我有点困惑,我不知道哪种方法最适合我的需要。所以,我想问你:
这两种查找位置的方法(如果有的话)有什么区别?
Android上的用户位置
在 Android 上获取用户的位置比在 iOS 上要简单一些。要开始混淆,有两种完全不同的方法可以做到这一点。第一个是使用 Android APIs android.location.LocationListener,第二个是使用 Google Play Services APIs com.google.android.gms.location.LocationListener。让我们通过他们两个。
android.location.LocationListener
com.google.android.gms.location.LocationListener
Android 的位置 API 使用三个不同的提供程序来获取位置 -
* `LocationManager.GPS_PROVIDER`——该提供商使用卫星确定位置。根据条件,此提供程序可能需要一段时间才能返回位置修复。 * `LocationManager.NETWORK_PROVIDER`' 该提供商根据手机信号塔和 WiFi 接入点的可用性确定位置。通过网络查找检索结果。 * `LocationManager.PASSIVE_PROVIDER`——此提供者将返回其他提供者生成的位置。当其他应用程序或服务请求位置更新时,您会被动地接收位置更新,而您自己却没有实际请求位置。
它的要点是你LocationManager从系统中获取一个对象,实现LocationListener,然后requestLocationUpdates在LocationManager.
LocationListener
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 指南 很好地解释了代码。但他们也提到,在大多数情况下,通过使用Google 定位服务 API,您将获得更好的电池性能以及更合适的准确度。现在混乱开始了!
Google 的 Location Services API 是 Google Play Services APK 的一部分(这里是如何设置它)。它们建立在 Android 的 API 之上。这些 API 提供了一个“使用的位置提供者”而不是上面提到的提供者。该提供程序会根据准确性、电池使用情况等自动选择要使用的底层提供程序。速度很快,因为您可以从不断更新它的系统范围的服务中获取位置。您可以使用更高级的功能,例如地理围栏。
要使用 Google 的定位服务,您的应用需要连接到GooglePlayServicesClient. 要连接到客户端,您的活动(或片段等)需要实现GooglePlayServicesClient.ConnectionCallbacks和GooglePlayServicesClient.OnConnectionFailedListener接口。这里是一个示例代码:
GooglePlayServicesClient
GooglePlayServicesClient.ConnectionCallbacks
GooglePlayServicesClient.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()
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()收到更新后立即关闭请求(在回调中)。
onConnected
onLocationChanged()
请注意,locationClient.requestLocationUpdates(locationRequest, this);必须在onConnected回调中,否则您将得到一个,IllegalStateException因为您将尝试在未连接到 Google Play 服务客户端的情况下请求位置。
locationClient.requestLocationUpdates(locationRequest, this);
IllegalStateException
很多时候,用户会禁用定位服务(为了节省电池或隐私原因)。在这种情况下,上面的代码仍然会请求位置更新,但onLocationChanged永远不会被调用。您可以通过检查用户是否禁用了位置服务来停止请求。
onLocationChanged
如果您的应用要求他们启用定位服务,您可能需要显示一条消息或祝酒词。遗憾的是,无法检查用户是否在 Google 的位置服务 API 中禁用了位置服务。为此,您将不得不求助于 Android 的 API。
在你的onCreate方法中:
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
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 。