Erweiterte Konzepte

Daten erheben

Es gibt viele Möglichkeiten, um an erfasste Standortdaten zu kommen. Hier werden zwei Techniken zum Abrufen von Daten beschrieben, die mit der Funktion An Straßen ausrichten von Roads API verwendet werden sollen.

GPX

GPX ist ein offenes XML-basiertes Format zum Teilen von Routen, Tracks und Wegpunkten, die mit GPS-Geräten erfasst wurden. In diesem Beispiel wird der XmlPull-Parser verwendet, ein schlanker 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 sind einige rohe GPX-Daten, die auf eine Karte geladen wurden.

Rohe GPX-Daten auf einer Karte

Android-Standortdienste

Die beste Methode zum Erfassen von GPS-Daten von einem Android-Gerät hängt vom Anwendungsfall ab. Sehen Sie sich den Android-Schulungskurs zum Empfangen von Standortaktualisierungen sowie die Google Play-Standortbeispiele auf GitHub an.

Lange Pfade verarbeiten

Da die Funktion An Straßen anpinnen den Standort anhand des vollständigen Pfades und nicht anhand einzelner Punkte ermittelt, müssen Sie bei der Verarbeitung langer Pfade (d. h. Pfade, die das Limit von 100 Punkten pro Anfrage überschreiten) vorsichtig sein.

Damit die einzelnen Anfragen als ein langer Pfad behandelt werden, sollten Sie eine gewisse Überschneidung vorsehen, sodass die Endpunkte der vorherigen Anfrage als erste Punkte der nachfolgenden Anfrage enthalten sind. Die Anzahl der einzubeziehenden Punkte hängt von der Genauigkeit Ihrer Daten ab. Bei Anfragen mit geringer Genauigkeit sollten Sie mehr Punkte angeben.

In diesem Beispiel werden mit dem Java-Client für Google Maps-Dienste paginated Anfragen gesendet und die Daten, einschließlich der interpolierten Punkte, werden dann in der zurückgegebenen Liste wieder zusammengeführt.

/**
 * 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 zum Anpassen an Straßen ausgeführt wurden. Die rote Linie sind die Rohdaten und die blaue Linie sind die aneinander angepaßten Daten.

Beispiel für Daten, die an Straßen angehängt wurden

Effiziente Nutzung des Kontingents

Die Antwort auf eine Anfrage zum Anpassen an Straßen enthält eine Liste von Orts-IDs, die den von Ihnen angegebenen Punkten zugeordnet sind, möglicherweise mit zusätzlichen Punkten, wenn Sie interpolate=true festgelegt haben.

Damit Sie Ihr zulässiges Kontingent für eine Anfrage zu Geschwindigkeitsbeschränkungen effizient nutzen können, sollten Sie in Ihrer Anfrage nur nach eindeutigen Orts-IDs fragen. 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 sind die Daten von oben mit Geschwindigkeitsbeschränkungen, die für jede eindeutige Orts-ID markiert sind.

Tempolimitschilder auf einer Karte

Interagieren mit anderen APIs

Einer der Vorteile der Rückgabe von Orts-IDs in den Snap to Straßen-Antworten besteht darin, dass die Orts-ID in vielen der Google Maps Platform APIs verwendet werden kann. In diesem Beispiel wird der Java-Client für Google Maps-Dienste verwendet, um einen Ort zu geocodieren, der von der obigen Anfrage zum Andocken an eine Straße 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;
}

Hier wurde die Markierung für das Tempolimit mit der Adresse aus der Geocoding API versehen.

Geocodierte Adresse, die auf einer Markierung angezeigt wird

Beispielcode

Hinweise

Der Code zur Unterstützung dieses Artikels ist zur Veranschaulichung als einzelne Android-App verfügbar. In der Praxis sollten Sie Ihre serverseitigen API-Schlüssel nicht in einer Android-App verteilen, da sie nicht vor unbefugtem Zugriff durch Dritte geschützt werden können. Um Ihre Schlüssel zu schützen, sollten Sie den API-Code stattdessen als serverseitigen Proxy bereitstellen und Ihre Android-App so konfigurieren, dass Anfragen über den Proxy gesendet werden. So können Sie dafür sorgen, dass Anfragen autorisiert werden.

Herunterladen

Laden Sie den Code von GitHub herunter.