9

我希望能够使用适用于 Android的Google Maps API显示两个用户定义的地理点之间的路线。我还希望能够让用户选择要显示的路线类型,无论是步行、骑自行车、汽车等。此外,我希望能够计算使用这条路线所需的时间和距离。我尝试在网上搜索并查看其他 stackoverflow 问题,但无济于事。我该怎么办?我怎么能编码这个。

// - - 编辑 - - //

我还想获取交通信息,例如繁忙的路线,拥堵等。

4

3 回答 3

6

这里有一些代码可以帮助你。

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

要使用 androidhttpclient 获取数据,请执行以下操作:

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;

其中 buildStringIOUtils 是:

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

然后,您可以使用以下内容从 JSON 响应中提取实际的折线:

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);
                        }
                    }

其中方法 decodePolyline 是这样的:

    /** 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;
    }

然后,您可以使用以下命令将折线添加到地图中:

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

要更改模式,请将其添加到 url(请参阅https://developers.google.com/maps/documentation/directions/):&mode=YOUR_MODE

驾驶(默认)指示使用道路网络的标准行车路线。

步行请求通过人行道和人行道(如果有)的步行路线。

骑自行车请求通过自行车道和首选街道(如果有)的自行车路线。

交通通过公共交通路线(如果可用)请求方向。

编辑:关于“我还想获取交通信息,例如繁忙的路线、拥堵等”。我还没有研究过这个,但我的代码应该能让你很好地开始。

编辑 2:在 google 方向 api 中找到:“对于行车路线:商业地图客户可以指定离开时间以接收考虑当前交通状况的行程持续时间。离开时间必须设置为当前时间的几分钟内。”

于 2013-04-19T08:31:44.890 回答
4

使用 Wrapper 库的 Android Google Maps Routing 示例代码

使用 Android Studio Gradle 入口:

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();
        }
    }

}

常量.java

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

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

}

活动地图.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>
于 2016-09-21T05:01:34.560 回答
3

试试Google Directions API。这是一项网络服务,它以 JSON 格式提供转弯指南,其中包含从 A 点到 B 点的汽车、公交或步行的所有信息。

遵循随机评论中的链接进行编码。

于 2013-04-13T17:53:55.860 回答