857 Stimmen

Was ist der einfachste und zuverlässigste Weg, um den aktuellen Standort des Benutzers unter Android zu ermitteln?

El LocationManager API auf Android scheint für eine Anwendung, die nur gelegentlich eine grobe Annäherung an den Standort des Nutzers benötigt, etwas mühsam zu sein.

Die App, an der ich arbeite, ist eigentlich keine Standort-App, aber sie muss den Standort des Benutzers abfragen, um eine Liste von Geschäften in der Nähe anzeigen zu können. Sie muss sich nicht darum kümmern, ob der Benutzer sich bewegt oder so etwas.

Ich würde gerne Folgendes tun:

  1. Zeigt dem Benutzer eine Liste von Orten in der Nähe.
  2. Den Standort des Nutzers vorladen, so dass er zum Zeitpunkt, an dem ich ihn in Activity X, wird es verfügbar sein.
  3. Die Genauigkeit und die Häufigkeit der Aktualisierungen sind mir nicht besonders wichtig. Es reicht aus, wenn ich nur einen Standort erfasse, solange er nicht weit daneben liegt. Wenn ich schick sein will, aktualisiere ich den Standort vielleicht einmal alle paar Minuten oder so, aber das hat keine große Priorität.
  4. Funktioniert mit jedem Gerät, das entweder über ein GPS oder einen Netzwerkstandortanbieter verfügt.

Es scheint, dass es nicht so schwer sein sollte, aber es scheint mir, dass ich zwei verschiedene Standortanbieter (GPS und NETZWERK) einrichten und den Lebenszyklus jedes Anbieters verwalten muss. Und nicht nur das, ich muss denselben Code in mehreren Aktivitäten duplizieren, um Nr. 2 zu erfüllen. Ich habe versucht, mit getBestProvider() Ich habe in der Vergangenheit versucht, die Lösung auf einen einzigen Standortanbieter zu beschränken, aber das scheint Ihnen nur den besten "theoretischen" Anbieter zu liefern und nicht den Anbieter, der Ihnen tatsächlich die besten Ergebnisse liefert.

Gibt es eine einfachere Möglichkeit, dies zu erreichen?

1 Stimmen

Sie könnten eine einfache Bibliothek verwenden, die all die Dinge abstrahiert, die "unter der Haube" passieren müssen: github.com/delight-im/Android-SimpleLocation

0 Stimmen

Hier finden Sie die Antwort in Kotlin: stackoverflow.com/a/53800632/2201814

0 Stimmen

Sie können in Android verschmolzene Techniken zur Standorterfassung verwenden.

0voto

Shailendra Madda Punkte 19055

Ich habe diesen GPS-Tracker verwendet, der von Android API 21 bis 30 ziemlich gut funktioniert:

  • Es funktioniert auch, wenn das Netzwerk deaktiviert und GPS aktiviert ist.
  • Funktioniert auch, wenn beide aktiviert sind :)
  • Fordert den Benutzer auf, GPS zu aktivieren, falls es nicht aktiviert ist, und führt ihn zu den GPS-Einstellungen
  • Ruft die Standortaktualisierungen bei Standortwechsel ab
  • Kann die Adresse aus Längen- und Breitengraden ermitteln
  • Gibt dem Netzbetreiber Vorrang und verbraucht weniger Akku
  • Sie können die Standortaktualisierung jederzeit stoppen.

Einfuhren:

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;

import java.util.List;
import java.util.Objects;

Hier ist die Klasse GPSTracker:

public class GPSTracker extends Service implements LocationListener, 
OnClickListener {

private final Context mContext;
private Location location = null;
protected LocationManager locationManager;
private double latitude;
private double longitude;
private boolean isGPSEnabled = false;
private boolean canGetLocation = false;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
private static final long MIN_TIME_BW_UPDATES = 1000 * 60; // 1 minute
private final String TAG = "GPSTracker";

public GPSTracker(Context context) {
    mContext = context;
    getLocation();
}

public Location getLocation() {
    try {
        locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
        // getting GPS status
        isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        // getting network status
        boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        if (isGPSEnabled || isNetworkEnabled) {
            this.canGetLocation = true;
            // if Network enabled lat/long using Network Provider
            if (isNetworkEnabled) {
                Log.d(TAG, "Network Provider");
                if (locationManager != null) {
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                    if (location != null) {
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                    }
                }
            } else { // if GPS Enabled get lat/long using GPS Services
                Log.d(TAG, "GPS Provider");
                locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER,
                        MIN_TIME_BW_UPDATES,
                        MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                if (locationManager != null) {
                    location = locationManager
                            .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                    if (location != null) {
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                    }
                }
            }
        } else {
            showSettingsAlert(this, this);
        }
    } catch (SecurityException e) {
        e.printStackTrace();
    }
    return location;
}

@Override
public void onLocationChanged(Location location) {
    latitude = location.getLatitude();
    longitude = location.getLongitude();
    Log.d(TAG, "Location changed: latitude: " + latitude + " , longitude: " + longitude);
}

@Override
public void onProviderDisabled(String provider) {
    Log.d(TAG, "onProviderDisabled called");
}

@Override
public void onProviderEnabled(String provider) {
    Log.d(TAG, "onProviderEnabled called");
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}

@Override
public IBinder onBind(Intent arg0) {
    return null;
}

/**
 * Function to get latitude
 */
public double getLatitude() {
    if (location != null) {
        latitude = location.getLatitude();
    }
    return latitude;
}

/**
 * Function to get longitude
 */
public double getLongitude() {
    if (location != null) {
        longitude = location.getLongitude();
    }
    return longitude;
}

/**
 * Function to check if best network provider
 *
 * @return boolean
 */
public boolean canGetLocation() {
    return this.canGetLocation;
}

/**
 * Function to show settings alert dialog
 */
public AlertDialog showSettingsAlert(
        OnClickListener _positiveButtonClickListener,
        OnClickListener _negativeButtonClickListener) {
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext);
    // Setting Dialog Title
    alertDialogBuilder.setTitle("GPS settings");
    // Setting Dialog Message
    alertDialogBuilder.setMessage("Please enable GPS to proceed.");
    // On pressing Settings button
    alertDialogBuilder.setPositiveButton("Settings",
            _positiveButtonClickListener);
    // on pressing cancel button
    alertDialogBuilder.setNegativeButton("Cancel", _negativeButtonClickListener);
    alertDialogBuilder.setCancelable(false);
    AlertDialog alertDialog = alertDialogBuilder.create();
    // Showing Alert Message
    alertDialogBuilder.show();
    return alertDialog;
}

/**
 * Function to show settings alert dialog
 */
public AlertDialog showGPSOffSettingsAlert(
        OnClickListener _positiveButtonClickListener,
        OnClickListener _negativeButtonClickListener) {
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext);
    // Setting Dialog Title
    alertDialogBuilder.setTitle("GPS settings");
    // Setting Dialog Message
    alertDialogBuilder.setMessage("Do you want to turn off GPS?");
    // On pressing Settings button
    alertDialogBuilder.setPositiveButton("Settings", _positiveButtonClickListener);
    // on pressing cancel button
    alertDialogBuilder.setNegativeButton("Cancel", _negativeButtonClickListener);
    alertDialogBuilder.setCancelable(false);
    AlertDialog alertDialog = alertDialogBuilder.create();
    // Showing Alert Message
    alertDialogBuilder.show();
    return alertDialog;
}

/**
 * Stop using GPS listener Calling this function will stop using GPS in your
 * app
 */
public void stopUsingGPS() {
    if (locationManager != null) {
        locationManager.removeUpdates(GPSTracker.this);
    }
}

public boolean isGPSEnabled() {
    return isGPSEnabled;
}

public boolean isGooglePlayServicesAvailable() {
    GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
    int status = googleApiAvailability.isGooglePlayServicesAvailable(mContext);
    if (status != ConnectionResult.SUCCESS) {
        if (googleApiAvailability.isUserResolvableError(status)) {
            Objects.requireNonNull(googleApiAvailability.getErrorDialog((Activity) mContext, status, 2404)).show();
        }
        return false;
    }
    return true;
}

public Address getAddress(double latitude, double longitude) {
    boolean networkAvailable = AppUtils.INSTANCE.isNetworkAvailable(mContext);
    Address address = new Address();
    if (!networkAvailable) {
        return address;
    }
    Geocoder geocoder = new Geocoder(mContext);
    try {
        List<android.location.Address> fromLocation = geocoder.getFromLocation(latitude, longitude, 1);
        if (fromLocation != null && !fromLocation.isEmpty()) {
            android.location.Address geoAddress = fromLocation.get(0);
            address.setAddress(geoAddress.getAddressLine(0));
            address.setCity(geoAddress.getLocality());
            address.setCountry(geoAddress.getCountryName());
            address.setPostalCode(geoAddress.getPostalCode());
            address.setKnownName(geoAddress.getFeatureName());
            address.setState(geoAddress.getAdminArea());
            address.setCountryCode(geoAddress.getCountryCode());
            address.setArea(geoAddress.getSubLocality());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return address;
}

@Override
public void onClick(DialogInterface dialog, int which) {
    if (which == dialog.BUTTON_POSITIVE) {
        mContext.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
    }
    dialog.dismiss();
}
}

Ermitteln Sie den Standort aus Ihrer Aktivität wie:

private fun getLocationInfo() {
    val gpsTracker = GPSTracker(this)
    if (gpsTracker.canGetLocation() && gpsTracker.isGooglePlayServicesAvailable) {
        val latitude = gpsTracker.latitude
        val longitude = gpsTracker.longitude
        val address = gpsTracker.getAddress(latitude, longitude)
        FileLogUtil(this).logInfo(
            "GPSTracker",
            "Latitude: $latitude , Longitude: $longitude , Address: ${address.address}"
        )
    }
}

Adressklasse:

public class Address {
    private String address;
    private String city;
    private String state;
    private String country;
    private String postalCode;
    private String knownName;
    private String countryCode;
    private String area;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public String getKnownName() {
        return knownName;
    }

    public void setKnownName(String knownName) {
        this.knownName = knownName;
    }

    public String getCountryCode() {
        return countryCode;
    }

    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }
}

Überprüfen Sie den Netzbetreiber wie folgt:

fun isNetworkAvailable(context: Context): Boolean {
        val connectivityManager =
            context.getSystemService(AppCompatActivity.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetworkInfo = connectivityManager.activeNetworkInfo
        return activeNetworkInfo != null && activeNetworkInfo.isConnected
    }

Vergessen Sie nicht, diese Berechtigungen im Manifest hinzuzufügen:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Wir können dies nutzen, um die erforderlichen Genehmigungen einzuholen:

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.util.*

class PermissionUtils(var activity: Activity) {

    private var permissionsList = arrayListOf<String>()

    companion object {
        const val REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124
        const val REQUEST_CALL_PERMISSION = 4
        fun isPermissionGranted(context: Context, permission: String): Boolean {
            val res = context.checkCallingOrSelfPermission(permission)
            return res == PackageManager.PERMISSION_GRANTED
        }
    }

    fun requestForAllMandatoryPermissions() {
        permissionsList = ArrayList<String>()
        //addPermissionIfNotGranted(Manifest.permission.CAMERA)
        //addPermissionIfNotGranted(Manifest.permission.CALL_PHONE)
        addPermissionIfNotGranted(Manifest.permission.ACCESS_FINE_LOCATION)
        addPermissionIfNotGranted(Manifest.permission.ACCESS_COARSE_LOCATION)
        //addPermissionIfNotGranted(Manifest.permission.READ_PHONE_STATE)
        //addPermissionIfNotGranted(Manifest.permission.READ_EXTERNAL_STORAGE)
        //addPermissionIfNotGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)

        if (permissionsList.isNotEmpty()) {
            ActivityCompat.requestPermissions(
                activity,
                permissionsList.toTypedArray(),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS
            )
        }
    }

    private fun addPermissionIfNotGranted(permission: String) {
        if (ContextCompat.checkSelfPermission(activity, permission) !=
            PackageManager.PERMISSION_GRANTED
        ) {
            permissionsList.add(permission)
            ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
        }
    }
}

Rufen Sie die Berechtigungen aus Ihrer Aktivität auf:

if (Build.VERSION.SDK_INT >= 23) {
    try {
        val permissionUtils = PermissionUtils(this)
        permissionUtils.requestForAllMandatoryPermissions()
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

-1voto

Dharmendra Pratap Punkte 507

Durch die Verwendung von FusedLocationProviderApi, der neuesten API und der besten unter den verfügbaren Möglichkeiten, den Standort in Android zu ermitteln. Fügen Sie dies in die Datei build.gradle ein

dependencies {
    compile 'com.google.android.gms:play-services:6.5.87'
}

Den vollständigen Quellcode erhalten Sie unter dieser Adresse http://javapapers.com/Android/Android-location-fused-provider/

-1voto

Bingerz Punkte 987

Kürzlich refactored, um den Standort des Codes zu erhalten, lernen einige gute Ideen, und schließlich erreicht eine relativ perfekte Bibliothek und Demo.

//request all valid provider(network/gps)
private boolean requestAllProviderUpdates() {
    checkRuntimeEnvironment();
    checkPermission();

    if (isRequesting) {
        EasyLog.d("Request location update is busy");
        return false;
    }

    long minTime = getCheckTimeInterval();
    float minDistance = getCheckMinDistance();

    if (mMapLocationListeners == null) {
        mMapLocationListeners = new HashMap<>();
    }

    mValidProviders = getValidProviders();
    if (mValidProviders == null || mValidProviders.isEmpty()) {
        throw new IllegalArgumentException("Not available provider.");
    }

    for (String provider : mValidProviders) {
        LocationListener locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                if (location == null) {
                    EasyLog.e("LocationListener callback location is null.");
                    return;
                }
                printf(location);
                mLastProviderTimestamp = location.getTime();

                if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
                    finishResult(location);
                } else {
                    doLocationResult(location);
                }

                removeProvider(location.getProvider());
                if (isEmptyValidProviders()) {
                    requestTimeoutMsgInit();
                    removeUpdates();
                }
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
            }

            @Override
            public void onProviderEnabled(String provider) {
            }

            @Override
            public void onProviderDisabled(String provider) {
            }
        };
        getLocationManager().requestLocationUpdates(provider, minTime, minDistance, locationListener);
        mMapLocationListeners.put(provider, locationListener);
        EasyLog.d("Location request %s provider update.", provider);
    }
    isRequesting = true;
    return true;
}

//remove request update
public void removeUpdates() {
    checkRuntimeEnvironment();

    LocationManager locationManager = getLocationManager();
    if (mMapLocationListeners != null) {
        Set<String> keys = mMapLocationListeners.keySet();
        for (String key : keys) {
            LocationListener locationListener = mMapLocationListeners.get(key);
            if (locationListener != null) {
                locationManager.removeUpdates(locationListener);
                EasyLog.d("Remove location update, provider is " + key);
            }
        }
        mMapLocationListeners.clear();
        isRequesting = false;
    }
}

//Compared with the last successful position, to determine whether you need to filter
private boolean isNeedFilter(Location location) {
    checkLocation(location);

    if (mLastLocation != null) {
        float distance = location.distanceTo(mLastLocation);
        if (distance < getCheckMinDistance()) {
            return true;
        }
        if (location.getAccuracy() >= mLastLocation.getAccuracy()
                && distance < location.getAccuracy()) {
            return true;
        }
        if (location.getTime() <= mLastProviderTimestamp) {
            return true;
        }
    }
    return false;
}

private void doLocationResult(Location location) {
    checkLocation(location);

    if (isNeedFilter(location)) {
        EasyLog.d("location need to filtered out, timestamp is " + location.getTime());
        finishResult(mLastLocation);
    } else {
        finishResult(location);
    }
}

//Return to the finished position
private void finishResult(Location location) {
    checkLocation(location);

    double latitude = location.getLatitude();
    double longitude = location.getLongitude();
    float accuracy = location.getAccuracy();
    long time = location.getTime();
    String provider = location.getProvider();

    if (mLocationResultListeners != null && !mLocationResultListeners.isEmpty()) {
        String format = "Location result:<%f, %f> Accuracy:%f Time:%d Provider:%s";
        EasyLog.i(String.format(format, latitude, longitude, accuracy, time, provider));

        mLastLocation = location;
        synchronized (this) {
            Iterator<LocationResultListener> iterator =  mLocationResultListeners.iterator();
            while (iterator.hasNext()) {
                LocationResultListener listener = iterator.next();
                if (listener != null) {
                    listener.onResult(location);
                }
                iterator.remove();
            }
        }
    }
}

Vollständiger Code: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

*Bei jeder Anfrage zur Vervollständigung der Ortung ist es am besten, Aktualisierungen zu entfernen, da sonst in der Statusleiste des Telefons immer das Ortungssymbol angezeigt wird.

-1voto

Khemraj Sharma Punkte 52006

Nachdem ich alle Antworten gesehen habe, und die Frage ( Einfach und robust ). Ich wurde nur über die Bibliothek angeklickt Android-ReactiveLocation .

Als ich eine App zur Standortverfolgung entwickelt habe. Dann erkannte ich, dass seine sehr typisch für Standortverfolgung mit optimiert mit Batterie zu behandeln.

Ich möchte also Neulingen und auch Entwicklern, die ihren Standortcode nicht mit zukünftigen Optimierungen pflegen wollen, dies mitteilen. Verwenden Sie diese Bibliothek.

ReactiveLocationProvider locationProvider = new 

    ReactiveLocationProvider(context);
    locationProvider.getLastKnownLocation()
        .subscribe(new Consumer<Location>() {
            @Override
            public void call(Location location) {
                doSthImportantWithObtainedLocation(location);
            }
        });

Abhängigkeiten, die in die build.gradle der Anwendungsebene aufgenommen werden müssen

dependencies {
    ...
    compile 'pl.charmas.android:android-reactive-location2:2.1@aar'
    compile 'com.google.android.gms:play-services-location:11.0.4' //you can use newer GMS version if you need
    compile 'com.google.android.gms:play-services-places:11.0.4'
    compile 'io.reactivex:rxjava:2.0.5' //you can override RxJava version if you need
}

Vorteile der Verwendung dieser Lib:

  • Diese Lib ist und wird aktiv gepflegt.
  • Machen Sie sich keine Sorgen um die Batterieoptimierung. Denn die Entwickler haben ihr Bestes getan.
  • Einfache Installation, Abhängigkeit und Spiel.
  • einfache Verbindung zur Play Services API
  • den letzten bekannten Standort ermitteln
  • für Standort-Updates abonnieren verwenden
  • Standort-Einstellungen API
  • Geofences verwalten
  • Geocodierung des Standorts in der Adressliste
  • Aktivitätserkennung
  • aktuellen Ort verwenden API Ort abrufen
  • Autovervollständigungsvorschläge

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X