Android 按下按钮获取高分辨率位置信息
Android get high resolution location info on button press
我已阅读 Android 文档,FusedLocationProvider
与 LocationManager
;在 Whosebug 中仔细阅读了围绕此主题的一系列令人眼花缭乱的问题和答案;并开发了许多测试,但迄今为止结果不佳。为什么这如此令人困惑和难以理解?
我有一个应用程序,当用户在应用程序中执行操作时需要获取高分辨率位置对象 (lat/long/alt/accuracy/etc);假设他们按下了一个按钮。最好的方法是什么?
我使用了 fusedLocationProviderClient.getLastLocation().addOnSuccessListener()
并得到了非常复杂的结果。
我用过locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
。如果我在我的 Galaxy S9 上启动 GPS 状态应用程序,那么这会产生非常好的结果。但如果那不是运行,那么结果就一文不值了。
我在这里错过了什么?每个人都喜欢指向这个 Doc 站点或那个 Example 站点,这些站点大多毫无价值并且没有真正回答这个特定问题。我浪费了几个小时浏览那些根本不回答这个问题的网站。请总结一下应该在此处使用的一般算法以及要进行的调用。这就是我所需要的。
我希望能够在我的院子里走动(这里和那里 10 米)并按下按钮并让应用程序显示 lat/long/accuracy/altitude/distance-from-last-location 并且每次都在一定水平内正确准确性。我需要做什么?我需要高分辨率精度,但能够通知用户小于 100 英尺的精度,并且即使有 400 英尺的误差,仍能获得尽可能好的精度。
您不知道 GPS 接收器的工作原理。
当没有应用使用精确定位时,所有智能phone都会关闭 GPS 接收器以节省电池电量。
即使您选择了打开位置服务(在设置中),您也会在通知栏中注意到 GPS 使用图标仅在应用处于活动状态时出现,例如 Google 地图或 GPS 测试应用
接收器打开后(因为某些应用程序需要它),需要一些时间才能"fix" - 准确的位置测量可用。
修复需要多长时间取决于多种因素,包括环境条件、您的 phone 类型、自上次准确修复以来的时间和距离等。
可能需要几秒到几分钟的时间。
因此,您应该做的是在您的应用程序打开后立即订阅位置,并请求尽可能频繁地接收它。
然后,只有当你的准确率很高时才启用按钮,当按下按钮时,显示最新的结果。
您可能还应该在等待准确修复时向用户显示一些微调器或消息,以便用户知道您的应用没有卡住。
编辑:"subscribe" 我的意思是注册必要的回调,以便您的应用在准备就绪时从系统接收位置信息。
如何操作,取决于您选择的API。
google 文档中没有错误。
如果您选择使用融合位置,则需要执行以下操作:
创建一个位置请求对象并将优先级设置为PRIORITY_HIGH_ACCURACY
,还将setInterval
和setFastestInterval
设置为1000(1秒)以获得最佳精度。
从LocationServices
获取一个FusedLocationProviderClient
对象
使用客户端向您的应用程序注册回调
这里有代码示例:
https://developer.android.com/training/location/request-updates
在您的应用程序的回调函数中,您可以检查准确性,如果它足够好,您可以启用按钮并保存位置,以便在用户单击按钮时将其显示给用户。
好的 - 这似乎有效。这个一般流程似乎就是答案。
假设:您在清单中请求 android.permission.ACCESS_FINE_LOCATION
或 ACCESS_COARSE_LOCATION
。
只是 MainActivity
的 onCreate()
函数中的示例代码用于测试目的。
- 检查我们是否有
ACCESS_FINE_LOCATION
许可;如果没有,请求。
- 得到
FusedLocationProviderClient
- 从
getLastLocation()
获取开始位置;用于比较和开始轨道
- 定义
locationCallback()
被fusedLocationProvider
调用;我们感兴趣的是获取堆栈中的最后一个并保存到 class 字段。
- 定义
LocationRequest
间隔为 5 秒和 PRIORITY_HIGH_ACCURACY
- 检查用户设备是否允许这样做;除了在不允许的情况下通知用户外,不知道该怎么办。
- 现在
requestLocationUpdates
使用上面定义的 LocationCallback
。
- 当用户执行需要当前 lat/long 的操作(例如按下按钮)时,检索 class 字段填充了最后一个
LocationCallback()
上的 Location 对象。
我非常愿意接受对此模式的反馈。希望它能帮助其他人(因为对此有很多问题)。并且很想听听有关此设计的任何问题或我可能遇到的问题。
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS);
} else {
// getFusedLocationProviderClient
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
// getStartLocation
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null) {
StartLocation.set(location);
}
}
}).addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
// Define LocationCallback
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
LastLocation = locationResult.getLastLocation();
}
}
};
// Now lets request location updates - that is how this must happen
// https://developer.android.com/training/location/change-location-settings
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Attempt to see if requested settings are compatible with user device.
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
// Check to see if location settings are satisfied by user's device settings?
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> locationTask = client.checkLocationSettings(builder.build())
.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
}
}).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.
}
Toast.makeText(MainActivity.this, "Location Settings Are Not " +
"Correct On This Device", Toast.LENGTH_LONG).show();
}
});
// Request location updates
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
}
}
我已阅读 Android 文档,FusedLocationProvider
与 LocationManager
;在 Whosebug 中仔细阅读了围绕此主题的一系列令人眼花缭乱的问题和答案;并开发了许多测试,但迄今为止结果不佳。为什么这如此令人困惑和难以理解?
我有一个应用程序,当用户在应用程序中执行操作时需要获取高分辨率位置对象 (lat/long/alt/accuracy/etc);假设他们按下了一个按钮。最好的方法是什么?
我使用了 fusedLocationProviderClient.getLastLocation().addOnSuccessListener()
并得到了非常复杂的结果。
我用过locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
。如果我在我的 Galaxy S9 上启动 GPS 状态应用程序,那么这会产生非常好的结果。但如果那不是运行,那么结果就一文不值了。
我在这里错过了什么?每个人都喜欢指向这个 Doc 站点或那个 Example 站点,这些站点大多毫无价值并且没有真正回答这个特定问题。我浪费了几个小时浏览那些根本不回答这个问题的网站。请总结一下应该在此处使用的一般算法以及要进行的调用。这就是我所需要的。
我希望能够在我的院子里走动(这里和那里 10 米)并按下按钮并让应用程序显示 lat/long/accuracy/altitude/distance-from-last-location 并且每次都在一定水平内正确准确性。我需要做什么?我需要高分辨率精度,但能够通知用户小于 100 英尺的精度,并且即使有 400 英尺的误差,仍能获得尽可能好的精度。
您不知道 GPS 接收器的工作原理。
当没有应用使用精确定位时,所有智能phone都会关闭 GPS 接收器以节省电池电量。
即使您选择了打开位置服务(在设置中),您也会在通知栏中注意到 GPS 使用图标仅在应用处于活动状态时出现,例如 Google 地图或 GPS 测试应用
接收器打开后(因为某些应用程序需要它),需要一些时间才能"fix" - 准确的位置测量可用。
修复需要多长时间取决于多种因素,包括环境条件、您的 phone 类型、自上次准确修复以来的时间和距离等。
可能需要几秒到几分钟的时间。
因此,您应该做的是在您的应用程序打开后立即订阅位置,并请求尽可能频繁地接收它。
然后,只有当你的准确率很高时才启用按钮,当按下按钮时,显示最新的结果。
您可能还应该在等待准确修复时向用户显示一些微调器或消息,以便用户知道您的应用没有卡住。
编辑:"subscribe" 我的意思是注册必要的回调,以便您的应用在准备就绪时从系统接收位置信息。
如何操作,取决于您选择的API。
google 文档中没有错误。 如果您选择使用融合位置,则需要执行以下操作:
创建一个位置请求对象并将优先级设置为
PRIORITY_HIGH_ACCURACY
,还将setInterval
和setFastestInterval
设置为1000(1秒)以获得最佳精度。从
LocationServices
获取一个使用客户端向您的应用程序注册回调
FusedLocationProviderClient
对象
这里有代码示例: https://developer.android.com/training/location/request-updates
在您的应用程序的回调函数中,您可以检查准确性,如果它足够好,您可以启用按钮并保存位置,以便在用户单击按钮时将其显示给用户。
好的 - 这似乎有效。这个一般流程似乎就是答案。
假设:您在清单中请求 android.permission.ACCESS_FINE_LOCATION
或 ACCESS_COARSE_LOCATION
。
只是 MainActivity
的 onCreate()
函数中的示例代码用于测试目的。
- 检查我们是否有
ACCESS_FINE_LOCATION
许可;如果没有,请求。 - 得到
FusedLocationProviderClient
- 从
getLastLocation()
获取开始位置;用于比较和开始轨道 - 定义
locationCallback()
被fusedLocationProvider
调用;我们感兴趣的是获取堆栈中的最后一个并保存到 class 字段。 - 定义
LocationRequest
间隔为 5 秒和PRIORITY_HIGH_ACCURACY
- 检查用户设备是否允许这样做;除了在不允许的情况下通知用户外,不知道该怎么办。
- 现在
requestLocationUpdates
使用上面定义的LocationCallback
。 - 当用户执行需要当前 lat/long 的操作(例如按下按钮)时,检索 class 字段填充了最后一个
LocationCallback()
上的 Location 对象。
我非常愿意接受对此模式的反馈。希望它能帮助其他人(因为对此有很多问题)。并且很想听听有关此设计的任何问题或我可能遇到的问题。
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS);
} else {
// getFusedLocationProviderClient
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
// getStartLocation
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null) {
StartLocation.set(location);
}
}
}).addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
// Define LocationCallback
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
LastLocation = locationResult.getLastLocation();
}
}
};
// Now lets request location updates - that is how this must happen
// https://developer.android.com/training/location/change-location-settings
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Attempt to see if requested settings are compatible with user device.
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
// Check to see if location settings are satisfied by user's device settings?
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> locationTask = client.checkLocationSettings(builder.build())
.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
}
}).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.
}
Toast.makeText(MainActivity.this, "Location Settings Are Not " +
"Correct On This Device", Toast.LENGTH_LONG).show();
}
});
// Request location updates
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
}
}