Android - 像 Google 地图一样准确获取坐标
Android - get coordinates accurately like Google Maps
如何像 Google 地图一样准确获取当前坐标?
到目前为止,我已经使用了 getLastLocation
- 它有效,但我得到了相同 20 米区域的相同坐标 - 它不是那么准确。在 Google 地图中,您可以看到大约 3 米的精度。我怎样才能做到这一点?
我只对坐标感兴趣
您需要做一些事情。确保你有权限,确保用户有他的 GPS 启用与否。您需要制作一个位置管理器和一个位置侦听器,每次更改时都会更新。请参阅下面的不同代码。
将此添加到清单文件以获取权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
创建位置管理器
LocationManager locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
检查 GPS 是否开启
try {
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch(Exception ex) {}
try {
network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch(Exception ex) {}
if(!gps_enabled && !network_enabled){
// It's not enabled address the problem here
}
创建监听器
LocationListener locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
侦听器Class示例代码
/*---------- Listener class to get coordinates ------------- */
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location loc) {
editLocation.setText("");
pb.setVisibility(View.INVISIBLE);
Toast.makeText(
getBaseContext(),
"Location changed: Lat: " + loc.getLatitude() + " Lng: "
+ loc.getLongitude(), Toast.LENGTH_SHORT).show();
String longitude = "Longitude: " + loc.getLongitude();
Log.v(TAG, longitude);
String latitude = "Latitude: " + loc.getLatitude();
Log.v(TAG, latitude);
/*------- To get city name from coordinates -------- */
String cityName = null;
Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
if (addresses.size() > 0) {
System.out.println(addresses.get(0).getLocality());
cityName = addresses.get(0).getLocality();
}
}
catch (IOException e) {
e.printStackTrace();
}
String s = longitude + "\n" + latitude + "\n\nMy Current City is: "
+ cityName;
editLocation.setText(s);
}
@Override
public void onProviderDisabled(String provider) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
用户授予位置权限后,您可以执行以下操作。
1- 要求用户启用 GPS 以获得高精度位置
2- 使用 fusedLocationProviderClient.getCurrentLocation() 方法获取用户当前位置
private fun askToEnableGPS() {
LocationServices.getSettingsClient(requireActivity())
.checkLocationSettings(
LocationSettingsRequest.Builder()
.addLocationRequest(LocationRequest.create().apply {
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}).build()
)
.addOnSuccessListener {
// GPS is already enable, callback GPS status through listener
getCurrentUserLocation()
}
.addOnFailureListener { e ->
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
// system open location
val rae = e as ResolvableApiException
launchGPS.launch(IntentSenderRequest.Builder(rae.resolution).build())
} catch (sie: IntentSender.SendIntentException) {
Log.i(
TAG,
"PendingIntent unable to execute request."
)
viewModel.handleNoGPS()
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
Log.i(
TAG,
"SETTINGS CHANGE UNAVAILABLE"
)
viewModel.handleNoGPS()
}
}
}
}
private val launchGPS =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
if (result.resultCode == AppCompatActivity.RESULT_OK) {
getCurrentUserLocation()
} else {
MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.gps_in_need_message))
.setPositiveButton(getString(R.string.confirm)) { dialog, _ ->
dialog.dismiss()
// retry here asking for GPS permission
}
.setNegativeButton(getString(R.string.get_default)) { dialog, _ ->
dialog.dismiss()
viewModel.handleNoGPS()
}
.setCancelable(false)
.show()
}
}
fun getCurrentUserLocation() {
fusedLocationProviderClient.getCurrentLocation(
LocationRequest.PRIORITY_HIGH_ACCURACY,
object : CancellationToken() {
override fun isCancellationRequested(): Boolean = false
override fun onCanceledRequested(p0: OnTokenCanceledListener): CancellationToken =
this
}
)
.addOnSuccessListener {
// here is user current location
viewModel.setSelectedByLocation(it.longitude, it.latitude)
}
.addOnFailureListener {
MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.failed_to_get_current_location))
.setPositiveButton(getString(R.string.retry)) { dialog, _ ->
dialog.dismiss()
// retry getCurrentUserLocation or askToEnableGPS
}
.setNegativeButton(getString(R.string.get_default)) { dialog, _ ->
dialog.dismiss()
// handle failure in getting current location
}
.setCancelable(false)
.show()
}
}
如何像 Google 地图一样准确获取当前坐标?
到目前为止,我已经使用了 getLastLocation
- 它有效,但我得到了相同 20 米区域的相同坐标 - 它不是那么准确。在 Google 地图中,您可以看到大约 3 米的精度。我怎样才能做到这一点?
我只对坐标感兴趣
您需要做一些事情。确保你有权限,确保用户有他的 GPS 启用与否。您需要制作一个位置管理器和一个位置侦听器,每次更改时都会更新。请参阅下面的不同代码。
将此添加到清单文件以获取权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
创建位置管理器
LocationManager locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
检查 GPS 是否开启
try {
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch(Exception ex) {}
try {
network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch(Exception ex) {}
if(!gps_enabled && !network_enabled){
// It's not enabled address the problem here
}
创建监听器
LocationListener locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
侦听器Class示例代码
/*---------- Listener class to get coordinates ------------- */
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location loc) {
editLocation.setText("");
pb.setVisibility(View.INVISIBLE);
Toast.makeText(
getBaseContext(),
"Location changed: Lat: " + loc.getLatitude() + " Lng: "
+ loc.getLongitude(), Toast.LENGTH_SHORT).show();
String longitude = "Longitude: " + loc.getLongitude();
Log.v(TAG, longitude);
String latitude = "Latitude: " + loc.getLatitude();
Log.v(TAG, latitude);
/*------- To get city name from coordinates -------- */
String cityName = null;
Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
if (addresses.size() > 0) {
System.out.println(addresses.get(0).getLocality());
cityName = addresses.get(0).getLocality();
}
}
catch (IOException e) {
e.printStackTrace();
}
String s = longitude + "\n" + latitude + "\n\nMy Current City is: "
+ cityName;
editLocation.setText(s);
}
@Override
public void onProviderDisabled(String provider) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
用户授予位置权限后,您可以执行以下操作。 1- 要求用户启用 GPS 以获得高精度位置 2- 使用 fusedLocationProviderClient.getCurrentLocation() 方法获取用户当前位置
private fun askToEnableGPS() {
LocationServices.getSettingsClient(requireActivity())
.checkLocationSettings(
LocationSettingsRequest.Builder()
.addLocationRequest(LocationRequest.create().apply {
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}).build()
)
.addOnSuccessListener {
// GPS is already enable, callback GPS status through listener
getCurrentUserLocation()
}
.addOnFailureListener { e ->
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
// system open location
val rae = e as ResolvableApiException
launchGPS.launch(IntentSenderRequest.Builder(rae.resolution).build())
} catch (sie: IntentSender.SendIntentException) {
Log.i(
TAG,
"PendingIntent unable to execute request."
)
viewModel.handleNoGPS()
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
Log.i(
TAG,
"SETTINGS CHANGE UNAVAILABLE"
)
viewModel.handleNoGPS()
}
}
}
}
private val launchGPS =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
if (result.resultCode == AppCompatActivity.RESULT_OK) {
getCurrentUserLocation()
} else {
MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.gps_in_need_message))
.setPositiveButton(getString(R.string.confirm)) { dialog, _ ->
dialog.dismiss()
// retry here asking for GPS permission
}
.setNegativeButton(getString(R.string.get_default)) { dialog, _ ->
dialog.dismiss()
viewModel.handleNoGPS()
}
.setCancelable(false)
.show()
}
}
fun getCurrentUserLocation() {
fusedLocationProviderClient.getCurrentLocation(
LocationRequest.PRIORITY_HIGH_ACCURACY,
object : CancellationToken() {
override fun isCancellationRequested(): Boolean = false
override fun onCanceledRequested(p0: OnTokenCanceledListener): CancellationToken =
this
}
)
.addOnSuccessListener {
// here is user current location
viewModel.setSelectedByLocation(it.longitude, it.latitude)
}
.addOnFailureListener {
MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.failed_to_get_current_location))
.setPositiveButton(getString(R.string.retry)) { dialog, _ ->
dialog.dismiss()
// retry getCurrentUserLocation or askToEnableGPS
}
.setNegativeButton(getString(R.string.get_default)) { dialog, _ ->
dialog.dismiss()
// handle failure in getting current location
}
.setCancelable(false)
.show()
}
}