7

Desidero poter visualizzare il percorso tra due punti geografici definiti dall'utente utilizzando l'API di Google Maps per Android. Voglio anche essere in grado di consentire all'utente di scegliere il tipo di percorso da visualizzare, che si tratti di camminare, andare in bicicletta, in auto, ecc. Inoltre, voglio essere in grado di calcolare il tempo e la distanza necessari per utilizzare questo percorso. Ho provato a cercare sul Web e a guardare altre domande StackOverflow, ma senza alcun risultato. Come andrei su questo? Come potrei essere in grado di codice questo.Trova percorso con Androids API di Google Maps

// ---- ---- EDIT //

Vorrei anche per ottenere informazioni sul traffico, come le rotte trafficate, congestione, ecc

+0

Ho seguito questo http://stackoverflow.com/questions/11745314/why-retrieving-google-directions-for-android-using-kml-data -non-funziona-anymo per ottenere il percorso. Questo è il primo passo. – Stochastically

risposta

3

Android Google Maps Routing codice di esempio utilizzando la libreria wrapper

utilizzare Android Studio Gradle entrata:

compile 'com.github.jd-alexander:library:1.1.0' 

MainActivity.java

import android.Manifest; 
import android.content.pm.PackageManager; 
import android.graphics.Color; 
import android.location.Location; 
import android.location.LocationListener; 
import android.location.LocationManager; 
import android.support.design.widget.FloatingActionButton; 
import android.support.design.widget.Snackbar; 
import android.support.v4.app.ActivityCompat; 
import android.support.v4.app.FragmentActivity; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.TextView; 
import android.widget.Toast; 

import com.directions.route.Route; 
import com.directions.route.RouteException; 
import com.directions.route.Routing; 
import com.directions.route.RoutingListener; 
import com.google.android.gms.maps.CameraUpdateFactory; 
import com.google.android.gms.maps.GoogleMap; 
import com.google.android.gms.maps.OnMapReadyCallback; 
import com.google.android.gms.maps.SupportMapFragment; 
import com.google.android.gms.maps.model.LatLng; 
import com.google.android.gms.maps.model.LatLngBounds; 
import com.google.android.gms.maps.model.Marker; 
import com.google.android.gms.maps.model.MarkerOptions; 
import com.google.android.gms.maps.model.Polyline; 
import com.google.android.gms.maps.model.PolylineOptions; 

import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 

public class MainActivity extends FragmentActivity implements OnMapReadyCallback, LocationListener, GoogleMap.OnMarkerClickListener, RoutingListener { 

    private GoogleMap mMap = null; 
    private LocationManager locationManager = null; 
    private FloatingActionButton fab = null; 
    private TextView txtDistance, txtTime; 

    //Global UI Map markers 
    private Marker currentMarker = null; 
    private Marker destMarker = null; 
    private LatLng currentLatLng = null; 
    private Polyline line = null; 

    //Global flags 
    private boolean firstRefresh = true; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_map); 
     Constants.POINT_DEST = new LatLng(18.758663, 73.382025);  //Lonavala destination. 
     //Load the map fragment on UI 
     SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); 
     mapFragment.getMapAsync(this); 
     txtDistance = (TextView)findViewById(R.id.txt_distance); 
     txtTime = (TextView)findViewById(R.id.txt_time); 
     fab = (FloatingActionButton)findViewById(R.id.fab); 
     fab.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       MainActivity.this.getRoutingPath(); 
       Snackbar.make(v, "Fetching Route", Snackbar.LENGTH_SHORT).show(); 
      } 
     }); 

    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     firstRefresh = true; 
     //Ensure the GPS is ON and location permission enabled for the application. 
     locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); 
     if (!PermissionCheck.getInstance().checkGPSPermission(this, locationManager)) { 
      //GPS not enabled for the application. 
     } else if (!PermissionCheck.getInstance().checkLocationPermission(this)) { 
      //Location permission not given. 
     } else { 
      Toast.makeText(MainActivity.this, "Fetching Location", Toast.LENGTH_SHORT).show(); 
      try { 
       locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); 
       locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 0, this); 
      } catch(Exception e) 
      { 
       Toast.makeText(MainActivity.this, "ERROR: Cannot start location listener", Toast.LENGTH_SHORT).show(); 
      } 
     } 
    } 

    @Override 
    protected void onPause() { 
     if (locationManager != null) { 
      //Check needed in case of API level 23. 

      if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
      } 
      try { 
       locationManager.removeUpdates(this); 
      } catch (Exception e) { 
      } 
     } 
     locationManager = null; 
     super.onPause(); 
    } 

    @Override 
    protected void onStop() { 
     super.onStop(); 
    } 

    @Override 
    public void onMapReady(GoogleMap googleMap) 
    { 
     mMap = googleMap; 
     //mMap.getUiSettings().setZoomControlsEnabled(true); 
     mMap.getUiSettings().setCompassEnabled(true); 
     mMap.getUiSettings().setAllGesturesEnabled(true); 
     mMap.setOnMarkerClickListener(this); 
    } 

    /** 
    * @desc LocationListener Interface Methods implemented. 
    */ 

    @Override 
    public void onLocationChanged(Location location) 
    { 
     double lat = location.getLatitude(); 
     double lng = location.getLongitude(); 
     currentLatLng = new LatLng(lat, lng); 
     if(firstRefresh) 
     { 
      //Add Start Marker. 
      currentMarker = mMap.addMarker(new MarkerOptions().position(currentLatLng).title("Current Position"));//.icon(BitmapDescriptorFactory.fromResource(R.drawable.location))); 
      firstRefresh = false; 
      destMarker = mMap.addMarker(new MarkerOptions().position(Constants.POINT_DEST).title("Destination"));//.icon(BitmapDescriptorFactory.fromResource(R.drawable.location))); 
      mMap.moveCamera(CameraUpdateFactory.newLatLng(Constants.POINT_DEST)); 
      mMap.animateCamera(CameraUpdateFactory.zoomTo(15)); 
      getRoutingPath(); 
     } 
     else 
     { 
      currentMarker.setPosition(currentLatLng); 
     } 
    } 

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

    @Override 
    public void onProviderEnabled(String provider) {} 

    @Override 
    public void onProviderDisabled(String provider) {} 

    /** 
    * @desc MapMarker Interface Methods Implemented. 
    */ 

    @Override 
    public boolean onMarkerClick(Marker marker) 
    { 
     if(marker.getTitle().contains("Destination")) 
     { 
      //Do some task on dest pin click 
     } 
     else if(marker.getTitle().contains("Current")) 
     { 
      //Do some task on current pin click 
     } 
     return false; 
    } 

    /** 
    *@desc Routing Listener interface methods implemented. 
    **/ 
    @Override 
    public void onRoutingFailure(RouteException e) 
    { 
     Toast.makeText(MainActivity.this, "Routing Failed", Toast.LENGTH_SHORT).show(); 
    } 

    @Override 
    public void onRoutingStart() { } 

    @Override 
    public void onRoutingSuccess(ArrayList<Route> list, int i) 
    { 
     try 
     { 
      //Get all points and plot the polyLine route. 
      List<LatLng> listPoints = list.get(0).getPoints(); 
      PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true); 
      Iterator<LatLng> iterator = listPoints.iterator(); 
      while(iterator.hasNext()) 
      { 
       LatLng data = iterator.next(); 
       options.add(data); 
      } 

      //If line not null then remove old polyline routing. 
      if(line != null) 
      { 
       line.remove(); 
      } 
      line = mMap.addPolyline(options); 

      //Show distance and duration. 
      txtDistance.setText("Distance: " + list.get(0).getDistanceText()); 
      txtTime.setText("Duration: " + list.get(0).getDurationText()); 

      //Focus on map bounds 
      mMap.moveCamera(CameraUpdateFactory.newLatLng(list.get(0).getLatLgnBounds().getCenter())); 
      LatLngBounds.Builder builder = new LatLngBounds.Builder(); 
      builder.include(currentLatLng); 
      builder.include(Constants.POINT_DEST); 
      LatLngBounds bounds = builder.build(); 
      mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50)); 
     } 
     catch (Exception e) 
     { 
      Toast.makeText(MainActivity.this, "EXCEPTION: Cannot parse routing response", Toast.LENGTH_SHORT).show(); 
     } 
    } 

    @Override 
    public void onRoutingCancelled() 
    { 
     Toast.makeText(MainActivity.this, "Routing Cancelled", Toast.LENGTH_SHORT).show(); 
    } 

    /** 
    * @method getRoutingPath 
    * @desc Method to draw the google routed path. 
    */ 
    private void getRoutingPath() 
    { 
     try 
     { 
      //Do Routing 
      Routing routing = new Routing.Builder() 
        .travelMode(Routing.TravelMode.DRIVING) 
        .withListener(this) 
        .waypoints(currentLatLng, Constants.POINT_DEST) 
        .build(); 
      routing.execute(); 
     } 
     catch (Exception e) 
     { 
      Toast.makeText(MainActivity.this, "Unable to Route", Toast.LENGTH_SHORT).show(); 
     } 
    } 

} 

Constants.java

/** 
* @class Constants 
* @desc Constant class for holding values at runtime. 
*/ 
public class Constants 
{ 

    //Map LatLong points 
    public static LatLng POINT_DEST = null; 

} 

activity_map.xml

<android.support.design.widget.CoordinatorLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:map="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools" 

android:layout_width="match_parent" 
android:layout_height="match_parent"> 

<LinearLayout android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <LinearLayout 
     android:id="@+id/viewA" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_weight="0.1" 
     android:orientation="horizontal"> 

     <fragment 
      android:id="@+id/map" 
      android:name="com.google.android.gms.maps.SupportMapFragment" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      tools:context="com.packagename.MainActivity" /> 


    </LinearLayout> 

    <LinearLayout 
     android:id="@+id/viewB" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_weight="0.9" 
     android:gravity="center|left" 
     android:paddingLeft="20dp" 
     android:background="#FFFFFF" 
     android:orientation="vertical" > 

     <TextView 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:textSize="16dp" 
      android:text="Distance ?" 
      android:paddingTop="3dp" 
      android:paddingLeft="3dp" 
      android:paddingBottom="3dp" 
      android:id="@+id/txt_distance" /> 

     <TextView 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:textSize="17dp" 
      android:paddingLeft="3dp" 
      android:text="Duration ?" 
      android:id="@+id/txt_time" /> 

    </LinearLayout> 

</LinearLayout> 

<android.support.design.widget.FloatingActionButton 
    android:id="@+id/fab" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_margin="16dp" 
    android:clickable="true" 
    android:src="@android:drawable/ic_dialog_map" 
    app:layout_anchor="@id/viewA" 
    app:layout_anchorGravity="bottom|right|end"/> 

</android.support.design.widget.CoordinatorLayout> 
3

Prova il Google Directions API. Si tratta di un servizio web, che fornisce guide turn-by-turn in formato JSON con tutte le informazioni per andare dal punto A al punto B in auto, in transito o ai piedi.

Per codice che segue il collegamento nel commento di Stocastico.

+2

Nell'introduzione all'API, si afferma "Questo servizio è generalmente progettato per calcolare le direzioni degli indirizzi statici (noti in anticipo) per il posizionamento del contenuto dell'applicazione su una mappa, questo servizio non è progettato per rispondere in tempo reale all'input dell'utente, Ad esempio, per i calcoli delle direzioni dinamiche (ad esempio, all'interno di un elemento dell'interfaccia utente), consultare la documentazione per il servizio Indicazioni V3 dell'API JavaScript. " – AndroidDev

+0

Sì, il punto è che l'API non è progettata per più chiamate in tempo reale. Basta chiamare l'API una volta, estrarre le informazioni da JSON e passarle in loop finché non si è arrivati. Come ho detto che l'API fornisce le informazioni, ma la logica per gestire tali informazioni deve essere implementata. –

+0

Hai visto la modifica? – AndroidDev

6

Ecco un codice per aiutarti.

String url= 
"http://maps.googleapis.com/maps/api/directions/json?origin=" 
+ origin.latitude + "," + origin.longitude +"&destination=" 
+ destination.latitude + "," + destination.longitude + "&sensor=false"; 

per recuperare i dati con androidhttpclient, fare qualcosa di simile:

HttpResponse response; 
HttpGet request; 
AndroidHttpClient client = AndroidHttpClient.newInstance("somename"); 

request = new HttpGet(url); 
response = client.execute(request); 

InputStream source = response.getEntity().getContent(); 
String returnValue = buildStringIOutils(source); 

return returnValue; 

dove buildStringIOUtils è:

private String buildStringIOutils(InputStream is) { 
    try { 
     return IOUtils.toString(is, "UTF-8"); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     return null; 
    } 
} 

È possibile quindi estrarre la poligonale reale dal JSON-risposta con qualcosa di simile:

JSONObject result = new JSONObject(returnValue); 
JSONArray routes = result.getJSONArray("routes"); 

        long distanceForSegment = routes.getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("distance").getInt("value"); 

        JSONArray steps = routes.getJSONObject(0).getJSONArray("legs") 
          .getJSONObject(0).getJSONArray("steps"); 

        List<LatLng> lines = new ArrayList<LatLng>(); 

        for(int i=0; i < steps.length(); i++) { 
         String polyline = steps.getJSONObject(i).getJSONObject("polyline").getString("points"); 

         for(LatLng p : decodePolyline(polyline)) { 
          lines.add(p); 
         } 
        } 

in cui il metodo decodePolyline è questo:

/** POLYLINE DECODER - http://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java **/ 
    private List<LatLng> decodePolyline(String encoded) { 

     List<LatLng> poly = new ArrayList<LatLng>(); 

     int index = 0, len = encoded.length(); 
     int lat = 0, lng = 0; 

     while (index < len) { 
      int b, shift = 0, result = 0; 
      do { 
       b = encoded.charAt(index++) - 63; 
       result |= (b & 0x1f) << shift; 
       shift += 5; 
      } while (b >= 0x20); 
      int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
      lat += dlat; 

      shift = 0; 
      result = 0; 
      do { 
       b = encoded.charAt(index++) - 63; 
       result |= (b & 0x1f) << shift; 
       shift += 5; 
      } while (b >= 0x20); 
      int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
      lng += dlng; 

      LatLng p = new LatLng((double) lat/1E5, (double) lng/1E5); 
      poly.add(p); 
     } 

     return poly; 
    } 

è quindi possibile aggiungere la polilinea alla mappa con questo:

Polyline polylineToAdd = mMap.addPolyline(new PolylineOptions().addAll(lines).width(3).color(Color.RED)); 

per cambiare la modalità, aggiungere questo all'URL (Vedere https://developers.google.com/maps/documentation/directions/): & mode = YOUR_MODE

guida (predefinita) indica le indicazioni stradali standard utilizzando la rete stradale.

passeggiate richieste indicazioni pedonali via pedonale & marciapiedi (ove disponibili).

le richieste di biciclette per le indicazioni ciclabili su percorsi ciclabili & strade preferite (ove disponibili).

richieste di transito indicazioni stradali tramite le vie di trasporto pubblico (ove disponibili).

Modifica: Informazioni su "Vorrei anche ottenere informazioni sul traffico come percorsi trafficati, congestione, ecc." Non ho esaminato questo, ma il mio codice dovrebbe farti iniziare abbastanza bene.

Edit2: Abbiamo trovato questo in google direzioni api: "per le indicazioni stradali:. Mappe per i clienti commerciali possono specificare il DEPARTURE_TIME per ricevere durata del viaggio considerando le condizioni di traffico attuali Il DEPARTURE_TIME deve essere impostato in pochi minuti del ora attuale."

+0

ciao, è possibile aggiungere più destinazione ?? –