问题描述
我想构建一个以获取用户当前位置为中心的应用,然后通过 Google Places API找到他/她附近的兴趣点(如酒吧、餐馆等)>.
I want to build an app that centers around getting the user's current location and then find points of interest(such as bars,restaurants,etc) that are close to him/her via the Google Places API.
在网上搜索起点时,我发现了一些使用 LocationManager
类的教程和其他一些使用 Google Play 服务 来查找用户的教程位置.
Upon searching the web for a place to start I came across some tutorials that use the LocationManager
class and some others that use Google Play Services in order to find the users location.
乍一看他们都做同样的事情,但由于我是新手,所以我有点困惑,我不知道哪种方法最适合我的需要.所以,我想问你:
On first sight both of them do the same thing, but since I am new to this I got a little confused and I don't know which method suits my needs the best. So, I want to ask you :
这两种查找位置的方法(如果有的话)有什么区别?
推荐答案
Android 上的用户位置
在 Android 上获取用户的位置比在 iOS 上要简单一些.要开始混淆,有两种完全不同的方法可以做到这一点.第一个是使用来自 android.location.LocationListener
的 Android API,第二个是使用 Google Play Services API com.google.android.gms.location.LocationListener
.让我们来看看它们.
Getting the user’s location on Android is a little less straightforward than on iOS. To start the confusion, there are two totally different ways you can do it. The first is using Android APIs from android.location.LocationListener
, and the second is using Google Play Services APIs com.google.android.gms.location.LocationListener
. Let’s go through both of them.
Android 的位置 API
Android 的位置 API 使用三个不同的提供程序来获取位置 -
The Android’s location APIs use three different providers to get location -
LocationManager.GPS_PROVIDER
— 此提供程序使用卫星确定位置.根据具体情况,此提供程序可能需要一段时间才能返回定位信息.LocationManager.NETWORK_PROVIDER
— 此提供商根据蜂窝塔和 WiFi 接入点的可用性确定位置.通过网络查找来检索结果.LocationManager.PASSIVE_PROVIDER
— 此提供程序将返回其他提供程序生成的位置.当其他应用程序或服务请求位置更新时,您会被动地接收位置更新,而您自己并没有实际请求位置.
LocationManager.GPS_PROVIDER
— This provider determines location using satellites. Depending on conditions, this provider may take a while to return a location fix.LocationManager.NETWORK_PROVIDER
— This provider determines location based on availability of cell tower and WiFi access points. Results are retrieved by means of a network lookup.LocationManager.PASSIVE_PROVIDER
— This provider will return locations generated by other providers. You passively receive location updates when other applications or services request them without actually requesting the locations yourself.
要点是从系统中获取LocationManager
的对象,实现LocationListener
,调用requestLocationUpdates
LocationManager
.
The gist of it is that you get an object of LocationManager
from the system, implement the LocationListener
, and call the requestLocationUpdates
on the LocationManager
.
这是一个代码片段:
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 代替.现在混乱开始了!
Google’s API Guide on Location Strategies explains the code pretty nicely. But they also mention that in most cases, you’ll get better battery performance, as well as more appropriate accuracy, by using the Google Location Services API instead. Now the confusion starts!
- Google 的定位服务 API
Google 的位置服务 API 是 Google Play 服务 APK 的一部分(方法如下设置它) .它们建立在 Android 的 API 之上.这些 API 提供了一个融合位置提供者",而不是上面提到的提供者.该提供程序会根据准确性、电池使用情况等自动选择要使用的底层提供程序.速度很快,因为您可以从不断更新它的系统范围的服务中获取位置.您还可以使用更高级的功能,例如地理围栏.
Google’s Location Services API is a part of the Google Play Services APK (here’s how to set it up) . They’re built on top of Android’s API. These APIs provide a "Fused Location Provider" instead of the providers mentioned above. This provider automatically chooses what underlying provider to use, based on accuracy, battery usage, etc. It is fast because you get location from a system-wide service that keeps updating it. And you can use more advanced features such as geofencing.
要使用 Google 的定位服务,您的应用需要连接到 GooglePlayServicesClient
.要连接到客户端,您的活动(或片段等)需要实现 GooglePlayServicesClient.ConnectionCallbacks
和 GooglePlayServicesClient.OnConnectionFailedListener
接口.这是一个示例代码:
To use the Google’s Location Services, your app needs to connect to the GooglePlayServicesClient
. To connect to the client, your activity (or fragment, or so) needs to implement GooglePlayServicesClient.ConnectionCallbacks
and GooglePlayServicesClient.OnConnectionFailedListener
interfaces.
Here’s a sample code:
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()
,则可能没有足够的时间让第一个位置进入.这将导致 location
为 null
.
The locationClient.getLastLocation()
gets the last known location from the client. However, the Fused Location Provider will only maintain background location if at least one client is connected to it. Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and you call getLastLocation()
right away in onConnected()
, that might not be enough time for the first location to come in. This will result in location
being null
.
要解决这个问题,您必须(不确定地)等待,直到提供者获取位置,然后调用 getLastLocation()
,这是不可能知道的.另一个(更好的)选择是实现 com.google.android.gms.location.LocationListener
接口以接收定期位置更新(并在获得第一次更新后将其关闭).
To solve this issue, you have to wait (indeterminately) till the provider gets the location and then call getLastLocation()
, which is impossible to know. Another (better) option is to implement the com.google.android.gms.location.LocationListener
interface to receive periodic location updates (and switch it off once you get the first update).
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()
回调中).
In this code, you’re checking if the client already has the last location (in onConnected
). If not, you’re requesting for location updates, and switching off the requests (in onLocationChanged()
callback) as soon as you get an update.
注意 locationClient.requestLocationUpdates(locationRequest, this);
必须在 onConnected
回调中,否则您将收到 IllegalStateException
因为您将尝试在未连接到 Google Play 服务客户端的情况下请求位置.
Note that the locationClient.requestLocationUpdates(locationRequest, this);
has to be inside the onConnected
callback, or else you will get an IllegalStateException
because you will be trying to request for locations without connected to the Google Play Services Client.
- 用户已禁用定位服务
很多时候,用户会禁用位置服务(为了节省电池或隐私原因).在这种情况下,上面的代码仍然会请求位置更新,但永远不会调用 onLocationChanged
.您可以通过检查用户是否禁用了定位服务来停止请求.
Many times, the user would have location services disabled (to save battery, or privacy reasons). In such a case, the code above will still request for location updates, but onLocationChanged
will never get called. You can stop the requests by checking if the user has disabled the location services.
如果您的应用要求它们启用定位服务,您可能需要显示一条消息或祝酒词.不幸的是,无法检查用户是否在 Google 的位置服务 API 中禁用了位置服务.为此,您将不得不求助于 Android 的 API.
If your app requires them to enable location services, you would want to show a message or a toast. Unfortunately, there is no way of checking if the user has disabled location services in Google’s Location Services API. For this, you will have to resort back to Android’s 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
标志,如下所示:
And use the locationEnabled
flag in your onConnected
method like this:
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:
Document is updated, LocationClient is removed and the api supports to enable GPS with one click from dialog:
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
New location client: FusedLocationProviderClient
private FusedLocationProviderClient fusedLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
建议通过https://developer.android.com/training/location 在执行任何定位任务之前.
It is recommended to go through https://developer.android.com/training/location before doing any location tasks.
这篇关于Android:LocationManager 与 Google Play 服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!