Erweiterte Konzepte

Daten erfassen

Es gibt viele Möglichkeiten, um an erfasste Standortdaten zu kommen. Hier werden zwei Techniken für die Erfassung von Daten beschrieben, die mit der Funktion An Straßen ausrichten von Roads API verwendet werden können.

GPX

GPX ist ein offenes XML-basiertes Format zum Teilen von Routen, Tracks und Wegpunkten, die von GPS-Geräten erfasst werden. In diesem Beispiel wird der Parser XmlPull verwendet, ein einfacher XML-Parser, der sowohl für Java-Server als auch für mobile Umgebungen verfügbar ist.

/**
 * Parses the waypoint (wpt tags) data into native objects from a GPX stream.
 */
private List<LatLng> loadGpxData(XmlPullParser parser, InputStream gpxIn)
        throws XmlPullParserException, IOException {
    // We use a List<> as we need subList for paging later
    List<LatLng> latLngs = new ArrayList<>();
    parser.setInput(gpxIn, null);
    parser.nextTag();

    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
            continue;
        }

        if (parser.getName().equals("wpt")) {
            // Save the discovered latitude/longitude attributes in each <wpt>.
            latLngs.add(new LatLng(
                    Double.valueOf(parser.getAttributeValue(null, "lat")),
                    Double.valueOf(parser.getAttributeValue(null, "lon"))));
        }
        // Otherwise, skip irrelevant data
    }

    return latLngs;
}

Hier sehen Sie GPX-Rohdaten, die in eine Karte geladen wurden.

GPX-Rohdaten auf einer Karte

Android-Standortdienste

Wie GPS-Daten am besten von einem Android-Gerät erfasst werden, hängt vom jeweiligen Anwendungsfall ab. Sehen Sie sich den Android-Schulungskurs zum Erhalten von Standortupdates sowie die Google Play-Standortbeispiele auf GitHub an.

Lange Pfade verarbeiten

Da die Funktion An Straßen ausrichten den Standort anhand des vollständigen Pfads und nicht anhand einzelner Punkte ableitet, müssen Sie bei der Verarbeitung langer Pfade (d. h. bei Pfaden mit mehr als 100 Punkten pro Anfrage) vorsichtig sein.

Damit die einzelnen Anfragen als ein langer Pfad behandelt werden, sollten Sie eine gewisse Überschneidung berücksichtigen, sodass die letzten Punkte aus der vorherigen Anfrage als erste Punkte der nachfolgenden Anfrage eingefügt werden. Die Anzahl der einzubeziehenden Punkte hängt von der Genauigkeit der Daten ab. Für Anfragen mit niedriger Genauigkeit sollten Sie mehr Punkte aufnehmen.

In diesem Beispiel wird der Java-Client für Google Maps-Dienste verwendet, um Paged-Anfragen zu senden. Die Daten, einschließlich interpolierter Punkte, werden dann in die zurückgegebene Liste aufgenommen.

/**
 * Snaps the points to their most likely position on roads using the Roads API.
 */
private List<SnappedPoint> snapToRoads(GeoApiContext context) throws Exception {
    List<SnappedPoint> snappedPoints = new ArrayList<>();

    int offset = 0;
    while (offset < mCapturedLocations.size()) {
        // Calculate which points to include in this request. We can't exceed the API's
        // maximum and we want to ensure some overlap so the API can infer a good location for
        // the first few points in each request.
        if (offset > 0) {
            offset -= PAGINATION_OVERLAP;   // Rewind to include some previous points.
        }
        int lowerBound = offset;
        int upperBound = Math.min(offset + PAGE_SIZE_LIMIT, mCapturedLocations.size());

        // Get the data we need for this page.
        LatLng[] page = mCapturedLocations
                .subList(lowerBound, upperBound)
                .toArray(new LatLng[upperBound - lowerBound]);

        // Perform the request. Because we have interpolate=true, we will get extra data points
        // between our originally requested path. To ensure we can concatenate these points, we
        // only start adding once we've hit the first new point (that is, skip the overlap).
        SnappedPoint[] points = RoadsApi.snapToRoads(context, true, page).await();
        boolean passedOverlap = false;
        for (SnappedPoint point : points) {
            if (offset == 0 || point.originalIndex >= PAGINATION_OVERLAP - 1) {
                passedOverlap = true;
            }
            if (passedOverlap) {
                snappedPoints.add(point);
            }
        }

        offset = upperBound;
    }

    return snappedPoints;
}

Hier sehen Sie die Daten von oben, nachdem die Anfragen für „Dem Straßenverlauf ausgerichtet“ ausgeführt wurden. Die rote Linie steht für die Rohdaten und die blaue Linie für die angedockten Daten.

Beispiel für Daten, die an Straßen ausgerichtet wurden

Effiziente Kontingentnutzung

Die Antwort auf eine Anfrage für das Andocken an Straßen enthält eine Liste von Orts-IDs, die den von Ihnen angegebenen Punkten zugeordnet sind. Wenn Sie interpolate=true festlegen, werden möglicherweise zusätzliche Punkte berücksichtigt.

Damit Sie das zulässige Kontingent effizient für Anfragen zu Geschwindigkeitsbegrenzungen nutzen können, sollten Sie in der Anfrage nur eindeutige Orts-IDs abfragen. In diesem Beispiel wird der Java-Client für Google Maps-Dienste verwendet, um Geschwindigkeitsbegrenzungen aus einer Liste von Orts-IDs abzufragen.

/**
 * Retrieves speed limits for the previously-snapped points. This method is efficient in terms
 * of quota usage as it will only query for unique places.
 *
 * Note: Speed limit data is only available for requests using an API key enabled for a
 * Google Maps APIs Premium Plan license.
 */
private Map<String, SpeedLimit> getSpeedLimits(GeoApiContext context, List<SnappedPoint> points)
        throws Exception {
    Map<String, SpeedLimit> placeSpeeds = new HashMap<>();

    // Pro tip: Save on quota by filtering to unique place IDs.
    for (SnappedPoint point : points) {
        placeSpeeds.put(point.placeId, null);
    }

    String[] uniquePlaceIds =
            placeSpeeds.keySet().toArray(new String[placeSpeeds.keySet().size()]);

    // Loop through the places, one page (API request) at a time.
    for (int i = 0; i < uniquePlaceIds.length; i += PAGE_SIZE_LIMIT) {
        String[] page = Arrays.copyOfRange(uniquePlaceIds, i,
                Math.min(i + PAGE_SIZE_LIMIT, uniquePlaceIds.length));

        // Execute!
        SpeedLimit[] placeLimits = RoadsApi.speedLimits(context, page).await();
        for (SpeedLimit sl : placeLimits) {
            placeSpeeds.put(sl.placeId, sl);
        }
    }

    return placeSpeeds;
}

Hier sehen Sie die Daten oben. Für jede eindeutige Orts-ID sind die Höchstgeschwindigkeiten gekennzeichnet.

Geschwindigkeitsbegrenzungen auf einer Karte

Mit anderen APIs interagieren

Orts-IDs, die in den Antworten des Typs An Straßen ausrichten zurückgegeben werden, haben unter anderem den Vorteil, dass Sie die Orts-ID für viele der Google Maps Platform APIs verwenden können. In diesem Beispiel wird der Java-Client für Google Maps-Dienste verwendet, um einen Ort zu geocodieren, der von der obigen Snap-to-Straße-Anfrage zurückgegeben wurde.

/**
 * Geocodes a snapped point using the place ID.
 */
private GeocodingResult geocodeSnappedPoint(GeoApiContext context, SnappedPoint point) throws Exception {
    GeocodingResult[] results = GeocodingApi.newRequest(context)
            .place(point.placeId)
            .await();

    if (results.length > 0) {
        return results[0];
    }
    return null;
}

Die Höchstgeschwindigkeitsmarkierung wurde in diesem Fall mit der Adresse aus der Geocoding API gekennzeichnet.

Geocodierte Adresse, die auf einer Markierung angezeigt wird

Beispielcode

Wissenswertes

Der Code für diesen Artikel ist zur Veranschaulichung als einzelne Android-App verfügbar. In der Praxis sollten Sie Ihre serverseitigen API-Schlüssel nicht in einer Android-App weitergeben, da sie nicht vor unbefugtem Zugriff durch Dritte geschützt werden können. Um Ihre Schlüssel zu sichern, sollten Sie stattdessen den API-seitigen Code als serverseitigen Proxy bereitstellen und Ihre Android-App Anfragen über den Proxy senden lassen. So stellen Sie sicher, dass Anfragen autorisiert sind.

Herunterladen

Laden Sie den Code von GitHub herunter.