Holen Sie sich den aktuellen Standort schnell und einmal in Android
Lesezeit: 14 Minuten
Mohamad MohamadPoor
Ich habe eine Android-Anwendung, die den aktuellen Standort des Geräts (Breiten- und Längengrad) benötigt. Ich habe einige Tutorials im Internet und insbesondere einige Lösungen von Stack Overflow ausprobiert, aber sie funktionieren bei mir nicht gut. Meine Anforderung ist so einfach: Zuerst muss es schnell gehen und ich brauche die Location einmal, wenn ich den Splitter starte. Zweitens muss es so genau wie möglich sein, ich meine, es sollte zuerst GPS verwenden, wenn GPS nicht verfügbar ist, und dann den Netzwerkanbieter verwenden.
Zum Beispiel habe ich diese Lösung ausprobiert, aber sie gibt nach 30 Sekunden null zurück, aber ich weiß, dass einige Dinge in Ordnung sind, weil Google Map und andere Anwendungen gut funktionieren !!!
Etwas, das fast alle Antworten vorschlagen, ist die Verwendung von getLastKnownLocation (), aber ich nehme an, es ist nicht das aktuelle und ich möchte es nicht, wenn es so ist.
kann mir jemand einen einfachen und schnellen Weg empfehlen, um den Ort nur EINMAL zu bekommen?!
Überprüfen Sie dies unter stackoverflow.com/a/53348535/6667442
– Ketan Ramani
1. Dezember 2018 um 4:40 Uhr
Innerhalb desselben obigen Threads gibt es ein Beispiel, das eine LocationProvider-Klasse verwendet, die Flexibilität für eine bis unendliche Standortaktualisierungen bietet.
– Mabz
14. Januar 2019 um 18:36 Uhr
Bitte sehen Sie sich den folgenden Link an https://stackoverflow.com/a/68096652/4042384 Ich hoffe, es wird Ihnen helfen
– GPU
23. Juni 2021 um 8:57 Uhr
Ashton Engberg
Hier können Sie dies verwenden …
Beispielnutzung:
public void foo(Context context) {
// when you need location
// if inside activity context = this;
SingleShotLocationProvider.requestSingleUpdate(context,
new SingleShotLocationProvider.LocationCallback() {
@Override public void onNewLocationAvailable(GPSCoordinates location) {
Log.d("Location", "my location is " + location.toString());
}
});
}
Vielleicht möchten Sie überprüfen, ob Lat/Long tatsächliche Werte sind und nicht 0 oder so. Wenn ich mich richtig erinnere, sollte dies kein NPE auslösen, aber Sie möchten das vielleicht überprüfen.
public class SingleShotLocationProvider {
public static interface LocationCallback {
public void onNewLocationAvailable(GPSCoordinates location);
}
// calls back to calling thread, note this is for low grain: if you want higher precision, swap the
// contents of the else and if. Also be sure to check gps permission/settings are allowed.
// call usually takes <10ms
public static void requestSingleUpdate(final Context context, final LocationCallback callback) {
final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isNetworkEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
@Override public void onStatusChanged(String provider, int status, Bundle extras) { }
@Override public void onProviderEnabled(String provider) { }
@Override public void onProviderDisabled(String provider) { }
}, null);
} else {
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
@Override public void onStatusChanged(String provider, int status, Bundle extras) { }
@Override public void onProviderEnabled(String provider) { }
@Override public void onProviderDisabled(String provider) { }
}, null);
}
}
}
// consider returning Location instead of this dummy wrapper class
public static class GPSCoordinates {
public float longitude = -1;
public float latitude = -1;
public GPSCoordinates(float theLatitude, float theLongitude) {
longitude = theLongitude;
latitude = theLatitude;
}
public GPSCoordinates(double theLatitude, double theLongitude) {
longitude = (float) theLongitude;
latitude = (float) theLatitude;
}
}
}
Um den SingleShotLocationProvider zu verbessern, fügen Sie entweder eine Berechtigungsprüfung zur Laufzeit hinzu oder lassen Sie die Methode eine mögliche SecurityException behandeln
– Bartburg
25. Januar 2016 um 10:20 Uhr
Danke, es funktioniert in Android 5 und niedriger. Aber ich kann es nicht auf Android 7 ausführen.
– MHSFisher
17. Oktober 2017 um 8:40 Uhr
Ist dies auch 2019 noch der beste/empfohlene Weg?
– Abhilash Kishore
21. November 2019 um 4:12 Uhr
As
Für alle, die daran interessiert sind, ein einzelnes Standort-Update auf die beste, idiomatische Weise mit den neuesten APIs und der Magie von Kotlin abzurufen, hier geht’s:
<manifest>
...
<!-- required only for LocationRequest.PRIORITY_HIGH_ACCURACY -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- required for all other priorities -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
...
</manifest>
Irgendwo in deinem Extensions Datei:
// To use PRIORITY_HIGH_ACCURACY, you must have ACCESS_FINE_LOCATION permission.
// Any other priority will require just ACCESS_COARSE_LOCATION,
// but will not guarantee a location update
@SuppressLint("MissingPermission")
suspend fun FusedLocationProviderClient.awaitCurrentLocation(priority: Int): Location? {
return suspendCancellableCoroutine {
// to use for request cancellation upon coroutine cancellation
val cts = CancellationTokenSource()
getCurrentLocation(priority, cts.token)
.addOnSuccessListener {location ->
// remember location is nullable, this happens sometimes
// when the request expires before an update is acquired
it.resume(location)
}.addOnFailureListener {e ->
it.resumeWithException(e)
}
it.invokeOnCancellation {
cts.cancel()
}
}
}
In deinem Fragment:
// need to register this anywhere before onCreateView, idealy as a field
private val permissionRequester = registerForActivityResult(
// you can use RequestPermission() contract if you only need 1 permission
ActivityResultContracts.RequestMultiplePermissions()
) { map ->
// If you requested 1 permission, change `map` to `isGranted`
// Keys are permissions Strings, values are isGranted Booleans
// An easy way to check if "any" permission was granted is map.containsValue(true)
// You can use your own logic for multiple permissions,
// but they have to follow the same checks here:
val response = map.entries.first()
val permission = response.key
val isGranted = response.value
when {
isGranted -> onPermissionGranted()
ActivityCompat.shouldShowRequestPermissionRationale(requireContext(), permission) -> {
// permission denied but not permanently, tell user why you need it.
// Idealy provide a button to request it again and another to dismiss
AlertDialog.Builder(requireContext())
.setTitle(R.string.perm_request_rationale_title)
.setMessage(R.string.perm_request_rationale)
.setPositiveButton(R.string.request_perm_again) { _, _ ->
requirePermission()
}
.setNegativeButton(R.string.dismiss, null)
.create()
.show()
}
else -> {
// permission permanently denied
// 1) tell user the app won't work as expected, or
// 2) take him to your app's info screen to manually change permissions, or
// 3) silently and gracefully degrade user experience
// I'll leave the implementation to you
}
}
}
onPermissionGranted-Funktion:
private fun onPermissionGranted() {
val lm = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
if(LocationManagerCompat.isLocationEnabled(lm)) {
// you can do this your own way, eg. from a viewModel
// but here is where you wanna start the coroutine.
// Choose your priority based on the permission you required
val priority = LocationRequest.PRIORITY_HIGH_ACCURACY
lifecycleScope.launch {
val location = LocationServices
.getFusedLocationProviderClient(requireContext())
.awaitCurrentLocation(priority)
// do whatever with this location, notice that it's nullable
}
} else {
// prompt user to enable location or launch location settings check
}
}
Jetzt müssen Sie nur noch Folgendes zum Klick-Listener für die MyLocation-Schaltfläche hinzufügen:
private fun requirePermission() {
val permissions = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
// optional: Manifest.permission.ACCESS_COARSE_LOCATION
)
permissionRequester.launch(permissions)
}
Beachten Sie, dass dies den Vorteil hat, zu überprüfen, ob die Erlaubnis bereits implizit erteilt wurde, und keinen Dialog/eine Anfrage anzuzeigen, wenn dies der Fall war. Ergo, starten Sie Ihren Flow immer, indem Sie den Requester starten, und führen Sie nur Ihre Überprüfungen in seinem Callback durch.
Wenn Sie eine Fehlermeldung erhalten, überprüfen Sie, ob Ihre build.gradle auf oberster Ebene einen Verweis auf das google()-Repo oder auf maven { url ” enthält.https://maven.google.com” }
override fun onCreate(savedInstanceState: Bundle?) {
...
LocationService.init(this)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
LocationService.onRequestPermissionsResult(this, requestCode, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
LocationService.onActivityResult(this, requestCode, resultCode)
}
private fun yourFunction() {
LocationService.getLocation(this, { location ->
//TODO: use the location
}, {
//TODO: display error message
})
}
Das ist genau das, was ich wollte. Es funktionierte sehr gut und bevor ich einen API-Aufruf tätigte, konnte ich Breiten- und Längengrad abrufen. Vielen Dank
public class MainActivity extends AppCompatActivity implements LocationListener {
private LocationManager locationManager;
private Location onlyOneLocation;
private final int REQUEST_FINE_LOCATION = 1234;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
}
@Override public void onLocationChanged(Location location) {
onlyOneLocation = location;
locationManager.removeUpdates(this);
}
@Override public void onStatusChanged(String provider, int status, Bundle extras) { }
@Override public void onProviderEnabled(String provider) { }
@Override public void onProviderDisabled(String provider) { }
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("gps", "Location permission granted");
try {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates("gps", 0, 0, this);
}
catch (SecurityException ex) {
Log.d("gps", "Location permission did not work!");
}
}
break;
}
}
Was Sie tun möchten, wird mit der erreicht LocationManager#requestSingleUpdate. Diese Methode hängt einen Listener in einem bestimmten Looper an (wenn Sie ihn wollen oder haben) und benachrichtigt den Ort so schnell wie möglich, nur einmal. Die von Ihnen vorgeschlagene Methode wird nur als ungenaue Position verwendet, bevor Ihnen die echte Position gegeben wird.
In jedem Fall wird es schneller als Millisekunden sein (es sei denn, Sie haben das Glück, mit dem Zuhören zu beginnen, wenn ein Ort zum Gerät kam). Stellen Sie sich das GPS als ein Element vor, das Sie aktivieren, wenn Sie auf Standorte warten, und deaktivieren, wenn Sie dieses Abhören entfernen. Dieses Verhalten wird durchgeführt, um ein Entladen des Akkus des Benutzers zu vermeiden.
Also zusammenfassend:
Die Zeit zwischen dem Hörbeginn und dem Empfang der Position hängt vom GPS des Geräts ab (Hersteller, Standort des Benutzers, Satellitenabdeckung…)
Es gibt eine Methode im Android SDK, um auf ein einzelnes Update zu warten.
Indem Sie ein Kriterienobjekt bereitstellen, können Sie verwalten, welche Kriterien für Sie akzeptabel sind, um einen Standort zu erhalten. Strengere Kriterien bedeuten mehr Zeit, um eine genaue Antwort zu erhalten.
Fabio sagt, Monica wieder einzusetzen
// Get LocationManager object
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Create a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Get the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Get Current Location
Location myLocation = locationManager.getLastKnownLocation(provider);
//latitude of location
double myLatitude = myLocation.getLatitude();
//longitude og location
double myLongitude = myLocation.getLongitude();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
Ajay Prabhakar
Alle obigen Antworten haben bei mir nicht funktioniert, daher habe ich dies beantwortet. Fügen Sie zunächst die Abhängigkeiten hinzu
Um diese Klasse zu verwenden, wird diese Methodenposition in der Adresszeichenfolge gespeichert
public void getLocation(){
Double latitude = 0.0, longitude;
String message = "";
LocationManager mlocManager = null;
LocationListener mlocListener;
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
latitude = MyLocationListener.latitude;
longitude = MyLocationListener.longitude;
message = message +"https://www.google.com/maps/dir/@"+ latitude +","+ longitude;
address=message;
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
if (latitude == 0.0) {
Toast.makeText(getApplicationContext(), "Currently gps has not found your location....", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(getApplicationContext(), "GPS is currently off...", Toast.LENGTH_LONG).show();
}
}
Hoffe es ist hilfreich
11799400cookie-checkHolen Sie sich den aktuellen Standort schnell und einmal in Androidyes
Überprüfen Sie dies unter stackoverflow.com/a/53348535/6667442
– Ketan Ramani
1. Dezember 2018 um 4:40 Uhr
Innerhalb desselben obigen Threads gibt es ein Beispiel, das eine LocationProvider-Klasse verwendet, die Flexibilität für eine bis unendliche Standortaktualisierungen bietet.
– Mabz
14. Januar 2019 um 18:36 Uhr
Bitte sehen Sie sich den folgenden Link an https://stackoverflow.com/a/68096652/4042384 Ich hoffe, es wird Ihnen helfen
– GPU
23. Juni 2021 um 8:57 Uhr