Android-Programmierung: Standortbestimmung mit der Google API
Willemers Informatik-Ecke

Manifest-Eintrag

Wenn die App den Standort bestimmen will, benötigt sie dafür eine Berechtigung, die in der Manifestdatei der App zu hinterlegen ist.

Im Projektordner app/manifests/AndroidManifest.xml anklicken. In der xml-Datei vor das Tag application ein Tag für die Benutzerberechtigungen (uses-permission) eintragen. Es wird die Berechtigung benötigt, den Standort sehr genau (ACCESS_FINE_LOCATION) oder wenigstens in etwa (ACCESS_COARSE_LOCATION) festzustellen.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.willemer.wobinich">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <application
...

Abhängigkeiten in build.gradle

Unter Gradle Scripts die Datei build.gradle (Module: app) anklicken. Dort wird in den Bereich dependencies { als letztes ein Verweis auf die Location-Dienste der Google-Play-Services eingetragen:
dependencies {
    implementation ...
    ...
    implementation 'com.google.android.gms:play-services-location:11.8.0'
}
Die Versionsnummer kann ein Problem darstellen. Aus diesem Grund kann es sinnvoll sein, die Bibliothek nicht direkt einzutragen, sondern über das Android Studio suchen zu lassen. Eventuell wird com.android.support:appcompat-v7 rot unterkringelt und vor Problemen gewarnt. Bei mir gab es keine.

Activity-Anpassungen

In der Activity, die die Position nutzen soll, muss geprüft werden, ob die API verfügbar ist. Dazu wird die Methode onCreate um einige Zeilen ergänzt:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        // API-Verfügbarkeit prüfen
        GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
        int result = availability.isGooglePlayServicesAvailable(this);
        if (result != ConnectionResult.SUCCESS) {
            if (!availability.isUserResolvableError(result)) {
                //  Hier Warnung ausgeben, dass die API nicht zugreifbar ist.
            }
        }
        // ...
    }
Beim Start der App wird überprüft, ob die App überhaupt das Recht hat, auf den Standort zu schauen.
int erlaubt = ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION);
if (erlaubt == PERMISSION_GRANTED) {
    holeStandort();
} else {
    // Erlaubnis noch nicht erteilt, frage nach!
    ActivityCompat.requestPermissions(this,
            new String[] { ACCESS_FINE_LOCATION },
            LOCATION_PERMISSION_REQUEST);
}
Die Request-Anforderung läuft asynchron. Um das Ergebnis zu erhalten, überschreiben Sie die Methode onRequestPermissionsResult der Activity, in der die Berechtigung erfragt wird.
@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == LOCATION_PERMISSION_REQUEST) {
        if (grantResults[0] != PERMISSION_GRANTED) {
            // Nur COARSE-Location erlaubt
            holeStandort();
        }
    }
}
Nachdem die Berechtigung erlangt ist, kann der Standort bestimmt werden. Dies übernimmt die Methode holeStandort, die oben bereits zwei Mal aufgerufen wurde.
void holeStandort() {
    FusedLocationProviderClient fusedLocationClient;
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    if (
        ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) ==PERMISSION_GRANTED
    ||
        ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION)==PERMISSION_GRANTED) {

        fusedLocationClient.getLastLocation().addOnSuccessListener(
                this, new OnSuccessListener() {
                @Override
                public void onSuccess(Location location) {
                    // location enthält die aktuelle Position
                }
        });
    }
}
Das ermittelte Objekt der Klasse Location kann mit den Methoden getLatitude und getLongitude nach der Position befragt werden.

Geocoder

Aus der Position Breiten- und Längengrad lässt sich über das Internet leicht ermitteln, wo man ist. Dazu wird die Berechtigung für das Internet benötigt, die in der Datei AndroidManifest.xml eingetragen sein muss:
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>
Die Wandlung übernimmt ein Geocoder, der mit der Regionsumgebung (Locale) erzeugt wird und der dann aus der Location eine Liste von Address macht, die an den Positionen für Breiten- und Längengrad zu finden sind. Meist interessiert nur die erste Adresse.

Jede Adresse kann wiederum nach der kompletten Adresszeile (getAdsressLine) oder Details wie Ort (getLocality), PLZ (getPostalCode) oder Land (getCountryName) befragt werden.

Die folgende Methode ermittelt die Adresse für die übergebene Location und erstellt daraus einen für den Benutzer lesbaren String. Durch Änderungen an der Variable adrZahl können auch mehrere Adressen geholt werden.

import android.location.Address;
import android.location.Geocoder;
import android.location.Location;

    // ...
String getAdressStr(Location location) {
    String antwort = "";
    if (location == null) {
        antwort = "Keine Location";
    } else if (!Geocoder.isPresent()) {
        antwort = "Kein Geocoder vorhanden";
    } else {
        Geocoder gc = new Geocoder(this, Locale.getDefault());
        try {
            int adrZahl = 1; // wie viele Adressen?
            List<Address> adressliste = gc.getFromLocation(
                    location.getLatitude(),
                    location.getLongitude(),
                    adrZahl);
            StringBuilder strSammel = new StringBuilder();
            for (int i=0; i<adressliste.size(); i++) {
                Address adr = adressliste.get(i);
                for (int j=0; j<adr.getMaxAddressLineIndex(); j++) {
                    strSammel.append(adr.getAddressLine(j)).append("\n");
                }
                strSammel.append(adr.getLocality()).append("\n");
                strSammel.append(adr.getPostalCode()).append("\n");
                strSammel.append(adr.getCountryName());
            }
            antwort = strSammel.toString();
        } catch (IOException e) {
            antwort = "IO-Exception";
        }
    }
    return antwort;
}