android - 如何在我的应用程序中使用 Google map 获取路线

标签 android google-maps google-maps-api-3

我目前正在开发一个需要 Google map 功能的 Android 应用程序,现在在我的 Android 代码中,我将纬度经度保存在 php 服务器中并检索回 Android 应用程序,它可以定位位置。现在我如何获取从当前位置到已从服务器设置位置的标记的方向?

当我单击标记时,屏幕右下角可以提供方向和 map ,但不是跳到给定的谷歌地图,我如何设置为我不想使用的当前谷歌地图另一个谷歌地图?

这是我的 Android Google map 代码:

public class MapsActivity3 extends FragmentActivity implements OnMapReadyCallback,
    com.google.android.gms.location.LocationListener,
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    GoogleMap.OnInfoWindowClickListener,
    GoogleMap.OnMarkerClickListener,
    GoogleMap.OnMapClickListener {

MapFragment mapFragment;
GoogleMap gMap;
MarkerOptions markerOptions = new MarkerOptions();
CameraPosition cameraPosition;
LatLng center, latLng;
String title;
LocationManager locationManager;
Marker mCurrLocationMarker;
Location mLastLocation;
LocationRequest mLocationRequest;

private GoogleApiClient mGoogleApiClient;

public static final String ID = "id";
public static final String TITLE = "name";
public static final String LAT = "lat";
public static final String LNG = "lng";

public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;

public static final String TAG = MapsActivity3.class.getSimpleName();

private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;

private Marker mSelectedMarker;

private String url = "http://192.168.1.2/gmaps/gmaps.php";

String tag_json_obj = "json_obj_req";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
            (this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }

    locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

    if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        Toast.makeText(this, "GPS is Enabled in your device", Toast.LENGTH_SHORT).show();
    } else {
        showGPSDisabledAlertToUser();
    }

}

private void showGPSDisabledAlertToUser() {
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
    alertDialogBuilder.setMessage("GPS is disabled in your device. Would you like to enable it?")
            .setCancelable(false)
            .setPositiveButton("Goto Settings Page To Enable GPS",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            Intent callGPSSettingIntent = new Intent(
                                    android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                            startActivity(callGPSSettingIntent);
                        }
                    });
    alertDialogBuilder.setNegativeButton("Cancel",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });
    AlertDialog alert = alertDialogBuilder.create();
    alert.show();
}

/**
 * Manipulates the map once available.
 * This callback is triggered when the map is ready to be used.
 * This is where we can add markers or lines, add listeners or move the camera. In this case,
 * we just add a marker near Sydney, Australia.
 * If Google Play services is not installed on the device, the user will be prompted to install
 * it inside the SupportMapFragment. This method will only be triggered once the user has
 * installed Google Play services and returned to the app.
 */
@Override
public void onMapReady(GoogleMap googleMap) {
    gMap = googleMap;

    center = new LatLng(4.583213, 101.094630);
    cameraPosition = new CameraPosition.Builder().target(center).zoom(15).build();
    googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

    getMarkers();

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){

        buildGoogleApiClient();
        gMap.setMyLocationEnabled(true);
        gMap.getUiSettings().setZoomControlsEnabled(true);
        gMap.getUiSettings().setCompassEnabled(true);

        //return;
    }
}

protected synchronized void buildGoogleApiClient() {
    //Toast.makeText(this, "buildGoogleApiClient", Toast.LENGTH_SHORT).show();
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

    //mGoogleApiClient.connect();
}

private void addMarker(LatLng latlng, final String title) {
    markerOptions.position(latlng);
    markerOptions.title(title);
    gMap.addMarker(markerOptions);

    gMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {

        @Override
        public void onInfoWindowClick(Marker marker) {
            Toast.makeText(getApplicationContext(), marker.getTitle(), Toast.LENGTH_LONG).show();

            Intent intent = new Intent(MapsActivity3.this, MainActivity.class);
            startActivity(intent);
        }
    });
}

private void moveToCurrentLocation(LatLng currentLocation)
{
    gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLocation,15));
    // Zoom in, animating the camera.
    gMap.animateCamera(CameraUpdateFactory.zoomIn());
    // Zoom out to zoom level 10, animating with a duration of 2 seconds.
    gMap.animateCamera(CameraUpdateFactory.zoomTo(15), 2000, null);

}

private void getMarkers() {
    StringRequest strReq = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {
            Log.e("Response: ", response.toString());

            try {
                JSONObject jObj = new JSONObject(response);
                String getObject = jObj.getString("location");
                JSONArray jsonArray = new JSONArray(getObject);

                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    title = jsonObject.getString(TITLE);
                    latLng = new LatLng(Double.parseDouble(jsonObject.getString(LAT)), Double.parseDouble(jsonObject.getString(LNG)));

                    addMarker(latLng, title);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e("Error" , error.getMessage());
            Toast.makeText(MapsActivity3.this, error.getMessage(), Toast.LENGTH_LONG).show();
        }
    });

    AppController.getInstance().addToRequestQueue(strReq, tag_json_obj);
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }

    Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

    if (mLastLocation != null) {
        //place marker at current position
        //mGoogleMap.clear();
        gMap.clear();
        latLng = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = gMap.addMarker(markerOptions);
        //mCurrLocationMarker = mLastLocation;
    }

    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(5000); //5 seconds
    mLocationRequest.setFastestInterval(5000); //5 seconds
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    mLocationRequest.setSmallestDisplacement(0.1F); //1/10 meter

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();

    /*
     * Google Play services can resolve some errors it detects.
     * If the error has a resolution, try sending an Intent to
     * start a Google Play services activity that can resolve
     * error.
     */
    if (connectionResult.hasResolution()) {
        try {
            // Start an Activity that tries to resolve the error
            connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
            /*
             * Thrown if Google Play services canceled the original
             * PendingIntent
             */
        } catch (IntentSender.SendIntentException e) {
            // Log the error
            e.printStackTrace();
        }
    } else {
        /*
         * If no resolution is available, display a dialog to the
         * user with the error.
         */
        Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
    }
}

@Override
public void onLocationChanged(Location location) {
    mLastLocation = location;
    if (mCurrLocationMarker != null) {
        mCurrLocationMarker.remove();
    }

    // Getting latitude of the current location
    double latitude = location.getLatitude();

    // Getting longitude of the current location
    double longitude = location.getLongitude();

    // Creating a LatLng object for the current location
    LatLng latLng = new LatLng(latitude, longitude);

    //LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    String provider = locationManager.getBestProvider(new Criteria(), true);

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
            (this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }

    Location locations = locationManager.getLastKnownLocation(provider);
    List<String> providerList = locationManager.getAllProviders();
    if (null != locations && null != providerList && providerList.size() > 0) {
        locations.getLongitude();
        locations.getLatitude();
        Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
        try {
            List<Address> listAddresses = geocoder.getFromLocation(latitude, longitude, 1);
            if (null != listAddresses && listAddresses.size() > 0) {

                // Here we are finding , whatever we want our marker to show when clicked
                String state = listAddresses.get(0).getAdminArea();
                String country = listAddresses.get(0).getCountryName();
                String subLocality = listAddresses.get(0).getSubLocality();
                markerOptions.title("" + latLng + "," + subLocality + "," + state + "," + country);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
    mCurrLocationMarker = gMap.addMarker(markerOptions);

    Toast.makeText(this, "Location Changed", Toast.LENGTH_SHORT).show();

    if (mGoogleApiClient != null){
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    }
}

@Override
public void onInfoWindowClick(Marker marker) {

}

@Override
public void onMapClick(LatLng latLng) {
    mSelectedMarker = null;
}

@Override
public boolean onMarkerClick(Marker marker) {
    return false;
}
}

嘿伙计们!当我在 php 上设置某些条件时,有没有办法更改标记颜色,例如:

ID 1 =“这里是空的!” (标记绿色) ID 2 =“已占用空间!” (标记红色)

顺便说一下,我可以显示两个带有两条不同消息的标记

已编辑

@Override
public void onMapReady(GoogleMap googleMap) {
    gMap = googleMap;
    gMap.setOnMarkerClickListener(this);

    center = new LatLng(4.583213, 101.094630);
    cameraPosition = new CameraPosition.Builder().target(center).zoom(15).build();
    googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

    getMarkers();

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){

        buildGoogleApiClient();
        gMap.setMyLocationEnabled(true);
        gMap.getUiSettings().setZoomControlsEnabled(true);
        gMap.getUiSettings().setCompassEnabled(true);

        //return;
    }
}

在MarkerClick上编辑

@Override
    public boolean onMarkerClick(Marker marker) {
    new DirectionsJSONParser();
    return true;
}

最佳答案

要获取方向/路径/路线,您需要谷歌地图方向 API。我已经在我的应用程序中完成了。所以我就粘贴到这里了。答案可能很长,但肯定会对您和其他人有所帮助。

编写一个解析 Directions API 响应的类。只需复制并粘贴此代码即可。这是 fragment link也是如此。

public class DirectionJSONParser {

public static final String ROUTES = "routes";
public static final String LEGS = "legs";
public static final String STEPS = "steps";
public static final String POLYLINE = "polyline";
public static final String POINTS = "points";


/**
 * Receives a JSONObject and returns a list of lists containing latitude and longitude
 * @param jObject JSONObject
 * @return List of routes
 */
public List<List<HashMap<String, String>>> parse(JSONObject jObject){

    List<List<HashMap<String, String>>> routes = new ArrayList<>();

    JSONArray jRoutes = null;
    JSONArray jLegs = null;
    JSONArray jSteps = null;

    try {

        jRoutes = jObject.getJSONArray(ROUTES);
        int jRoutesLength = jRoutes.length();
        // Traversing all routes
        for(int i=0; i<jRoutesLength; i++){

            jLegs = ((JSONObject)jRoutes.get(i)).getJSONArray(LEGS);

            List path = new ArrayList<HashMap<String, String>>();

            int jLegsLength = jLegs.length();
            // Traversing all legs
            for (int j = 0; j<jLegsLength; j++){

                jSteps = ((JSONObject)jLegs.get(j)).getJSONArray(STEPS);

                int jStepsLength = jSteps.length();
                // Traversing all steps
                for (int k = 0; k<jStepsLength; k++){
                    String polyline = "";
                    polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get(POLYLINE)).get(POINTS);
                    List<LatLng> list = decodePoly(polyline);

                    for (int l = 0; l<list.size(); l++){
                        HashMap<String, String> hm = new HashMap<>();
                        hm.put("lat",Double.toString((list.get(l)).latitude));
                        hm.put("lng",Double.toString((list.get(l)).longitude));
                        path.add(hm);
                    }
                }
            }
            routes.add(path);
        }


    } catch (JSONException ex){
        ex.printStackTrace();
    }
    return routes;
}

/**
 * Method to decode polyline points
 * Courtesy : http://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java
 * */
private List<LatLng> decodePoly(String encoded) {

    List<LatLng> poly = new ArrayList<>();
    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;
 }
}

获取路线 url。它将生成完整的 URL 来调用 api。

private String getDirectionsUrl(LatLng origin, LatLng destination) {
    //https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&key=YOUR_API_KEY
    //Origin
    String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
    //Destination
    String str_destination = "destination=" + destination.latitude + "," + destination.longitude;
    // Set output format
    String output = "json";

    String api_key = "key=" + getString(R.string.google_maps_key);

    //Building the parameters to the web service
    String parameters = output + "?" + str_origin + "&" + str_destination + "&" + api_key;

    String url = "https://maps.googleapis.com/maps/api/directions/" + parameters;

    return url;
}

编写一个调用此 url 并获取响应的方法。

private String downloadUrl(String strUrl) throws IOException {

    String data = "";
    InputStream iStream = null;
    HttpURLConnection urlConnection = null;

    try {

        URL url = new URL(strUrl);

        // Creating an HTTP Connection to communicate with url
        urlConnection = (HttpURLConnection) url.openConnection();

        //Connecting to URL
        urlConnection.connect();

        // Reading data from URL
        iStream = urlConnection.getInputStream();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(iStream));

        StringBuilder sb = new StringBuilder();

        String line = "";

        while ((line = bufferedReader.readLine()) != null) {
            sb.append(line);
        }

        data = sb.toString();

        bufferedReader.close();
    } catch (Exception e) {
        Log.d("Exception", e.toString());
    } finally {
        iStream.close();
        urlConnection.disconnect();
    }

    return data;
}

由于这是网络调用,因此在单独的线程中调用它:

 /**
 * Fetches data from URL passed
 */
private class DownloadTask extends AsyncTask<String, Void, String> {

    // Downloading data in non-UI thread
    @Override
    protected String doInBackground(String... url) {
        String data = "";
        try {
            data = downloadUrl(url[0]);
        } catch (Exception e) {
            Log.d("Background Task", e.toString());
        }
        return data;
    }

    @Override
    protected void onPostExecute(String result) {

        ParserTask parserTask = new ParserTask();

        // Invokes the thread for pars;ing JSON data
        parserTask.execute(result);
    }
}

最后,看到onPostExecute()方法,它正在调用ParserTask,这里是:

private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {

    // Parsing the data in non-ui thread
    @Override
    protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {

        JSONObject jObject;
        List<List<HashMap<String, String>>> routes = null;

        try {
            jObject = new JSONObject(jsonData[0]);
            DirectionJSONParser parser = new DirectionJSONParser();
            routes = parser.parse(jObject);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return routes;
    }

    // Executes in UI thread, after the parsing process
    @Override
    protected void onPostExecute(List<List<HashMap<String, String>>> result) {


        ArrayList<LatLng> points;
        PolylineOptions lineOptions = null;
        int resultSize = result.size();

        //Traversing through all the routes
        for (int i = 0; i < resultSize; i++) {

            points = new ArrayList<>();
            lineOptions = new PolylineOptions();

            //Fetching i-th route
            List<HashMap<String, String>> path = result.get(i);

            int pathSize = path.size();
            // Fetching all the points in i-th route
            for (int j = 0; j < pathSize; j++) {
                HashMap<String, String> point = path.get(j);
                double lat = Double.parseDouble(point.get("lat"));
                double lng = Double.parseDouble(point.get("lng"));

                LatLng position = new LatLng(lat, lng);

                points.add(position);
            }

            // Adding all the points in the route to LineOptions
            lineOptions.addAll(points);
            lineOptions.width(5);
            lineOptions.color(Color.BLUE);
        }

        if (lastPolyLine != null) {
            lastPolyLine.remove();
        }
        // Drawing polyline in the Google Map for the i-th route
        lastPolyLine = mMap.addPolyline(lineOptions);
//            mMap.addPolyline(lineOptions);

    }
}

其中 lastPolyLinecom.google.android.gms.maps.model.Polyline 类型。

注意:

if (lastPolyLine != null) {
                lastPolyLine.remove();
            }  

如果您不进行此检查,则每次单击标记时都会有多个路径。

在您的 onMapReady() 方法中,设置标记点击监听器并实现 onMarkerClick():

mMap.setOnMarkerClickListener(this);

@Override
public boolean onMarkerClick(Marker marker) {

    Log.i(TAG, "On Marker Click");

    LatLng origin = new LatLng(myLocation.getLatitude(), myLocation.getLongitude());
    LatLng destination = marker.getPosition();

    // Getting URL to the Google Directions API
    String url = getDirectionsUrl(origin, destination);

    DownloadTask downloadTask = new DownloadTask();

    // Start downloading json data from Google Directions API
    downloadTask.execute(url);

    return true;
}

关于android - 如何在我的应用程序中使用 Google map 获取路线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45548206/

相关文章:

choroplethr、ggmap 或 ggplot2 中的道路和半径圆

javascript - Google Map API - 获取有关一个坐标的信息

google-maps-api-3 - 使用免费的 gmaps 帐户每秒可以执行多少个请求?

android - 加载屏幕直到 map 出现

java - 更改录制音频的音高和频率

android:无法制作多线芯片组

Android,将音轨添加到 Muxer

ios - 在 Google map 中创建标记

java - 获取随机 getmapASync 空指针异常

java - getReseources() 位图数组出现 NullPointerException