Answers:
Android上的用户位置
在Android上获取用户的位置比在iOS上简单一些。要开始造成混乱,可以使用两种完全不同的方法。第一种是使用来自的Android API android.location.LocationListener
,第二种是使用Google Play服务API com.google.android.gms.location.LocationListener
。让我们来看看它们两者。
Android的位置API
Android的位置API使用三种不同的提供程序来获取位置-
LocationManager.GPS_PROVIDER
—该提供商使用卫星确定位置。根据条件,此提供程序可能需要一段时间才能返回位置修复。LocationManager.NETWORK_PROVIDER
—该提供商根据蜂窝塔和WiFi接入点的可用性确定位置。通过网络查找来检索结果。LocationManager.PASSIVE_PROVIDER
—该提供者将返回其他提供者生成的位置。当其他应用程序或服务请求位置更新时,您会被动接收位置更新,而无需自己实际请求位置。其要点是您LocationManager
从系统中获取的对象,实施LocationListener
,然后在requestLocationUpdates
上调用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指南很好地解释了代码。但是他们也提到,在大多数情况下,通过使用Google Location Services API,您可以获得更好的电池性能以及更合适的准确性。现在混乱开始了!
Google的位置服务API是Google Play服务APK的一部分(以下是设置方法)。它们建立在Android API之上。这些API提供了“融合位置提供程序”,而不是上面提到的提供程序。该提供程序会根据准确性,电池使用情况等自动选择要使用的基础提供程序。这是快速的,因为您可以从不断更新它的系统范围服务中获取位置。您可以使用更高级的功能,例如地理围栏。
要使用Google的位置服务,您的应用需要连接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()
得到来自客户端的最后已知位置。但是,只有在至少一个客户端与其连接的情况下,融合位置提供程序才会维护后台位置。一旦第一个客户端连接,它将立即尝试获取位置。如果您的活动是第一个客户端连接,并调用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的Location Services 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。
SettingsApi.checkLocationSettings()
用来检查用户是否已启用位置服务(请参阅此处:developers.google.com/android/reference/com/google/android/gms/…)。
LocationManager
。融合的位置api是否可以在没有Google Play服务的设备上使用?
fun isLocationEnabled(context: Context): Boolean { val locationMode: Int try { locationMode = Settings.Secure.getInt( context.contentResolver, Settings.Secure.LOCATION_MODE ) } catch (e: SettingNotFoundException) { e.printStackTrace() return false } return locationMode != Settings.Secure.LOCATION_MODE_OFF }
以我的经验,“更适当的准确性”绝不意味着更好。除非我缺少任何东西,否则如果要确保使用GPS,则LocationManager是唯一的选择。我们会使用我们的应用程序来跟踪车辆,并且再次提醒您,除非我遗漏了一些东西,否则Google Play服务经常会提供一些非常不准确的位置。
您应该使用Google Play服务位置api而不是LocationManager。根据文档:
Google Play服务位置API比Android框架位置API(android.location)更为可取,可为您的应用增加位置感知功能。如果您当前正在使用Android框架位置API,则强烈建议您尽快切换到Google Play服务位置API。
至于为什么要切换,谷歌说:
作为Google Play服务的一部分的Google Location Services API提供了更强大的高级框架,该框架可自动处理位置提供者,用户移动和位置准确性。它还根据您提供的功耗参数处理位置更新计划。在大多数情况下,通过使用Location Services API,您将获得更好的电池性能以及更合适的精度。
我已经使用Google定位服务API已有一段时间了。它确实具有优势,因为它封装了具有多个用于确定位置的来源的复杂性。但是,它封装得太重,因此当您获得一个奇怪的位置时,您将无法确定该奇怪位置的来源。
在现实生活中,我弹出了几个怪胎值,离实际位置10公里。唯一的解释是,这些疯狂的地点源于Google Wi-Fi或NWK数据库中的错误-由于Wi-Fi和网络拓扑每天都在变化,因此错误始终存在。但是不幸的是(而且令人惊讶的是)API没有提供有关如何得出个人头寸的信息。
这给您带来了必须根据对速度,加速度,轴承等的合理性检查来过滤出异常值的问题。
...或者回到旧的框架API并仅使用GPS,这是我决定在Google改进融合API之前所做的事情。
Google Location Services API是Google Play服务的一部分,它提供了功能更强大的高级框架,可自动处理位置提供者,用户移动和位置准确性。它还根据您提供的功耗参数处理位置更新计划。在大多数情况下,通过使用Location Services API,您将获得更好的电池性能以及更合适的精度。
基于GPS服务的两个API Google Play服务位置API和Android框架位置API之间的区别
FusedLocationProviderClient
requestLocationUpdates()
方法来访存位置。locationRequest.setInterval(milliseconds)
和setFastestInterval(milliseconds)
,而不基于用户位置更改LocationManager Api
根据用户位置更改和时间间隔获取位置 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, milliseconds, mindistance, Mylocationlistener)
返回的LatLng值包含14个十进制值 (例如:11.94574594963342 79.81166719458997) 准确的位置值