I'm currently developing an android app that require Google Maps feature, right now in my android code, i saved the latitude longitude in php server and retrieve back into android app, and it can locate the position. Right now how do i get the direction from my current location to the marker that already set the position from the server?
我目前正在开发一个需要谷歌地图功能的Android应用程序,现在在我的Android代码中,我在php服务器中保存了经度并检索回到Android应用程序,它可以找到位置。现在我如何从当前位置获取已经从服务器设置位置的标记的方向?
When i click the marker, there is bottom right corner of the screen that can give direction and map but instead of jumping on to the given google map, how do i set to my current google map which i do not want to use the other google map?
当我点击标记时,屏幕的右下角可以给出方向和地图,但不是跳到给定的谷歌地图,我如何设置到我当前的谷歌地图,我不想使用其他谷歌地图?
Here is my Android Google Map Code:
这是我的Android Google地图代码:
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;
}
}
Hey guys! Is there a way to change the marker color when i set certain condition on my php like for example:
大家好!当我在我的php上设置某些条件时,有没有办法更改标记颜色,例如:
ID 1 = "Empty space here!" (marker green color) ID 2 = "Space occupied!" (marker red color)
ID 1 =“这里空的空间!” (标记绿色)ID 2 =“占用空间!” (标记红色)
By the way, i can display two marker with two different message
顺便说一下,我可以用两个不同的信息显示两个标记
Edited
编辑
@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;
}
}
Edit onMarkerClick
编辑onMarkerClick
@Override
public boolean onMarkerClick(Marker marker) {
new DirectionsJSONParser();
return true;
}
2 个解决方案
#1
0
To get direction from one lat,lng location to another, you have to use Google direction api. For simplicity of parsing api response use google-maps-services-java library and draw polyline on Map. Following link is very help full for this https://android.jlelse.eu/google-maps-directions-api-5b2e11dee9b0
要从一个lat,lng位置到另一个位置获取方向,您必须使用Google方向api。为了简化解析api响应,请使用google-maps-services-java库并在Map上绘制折线。以下链接非常有用,请访问https://android.jlelse.eu/google-maps-directions-api-5b2e11dee9b0
#2
0
To get the direction/path/route, you need google maps directions API. I have done it in my app. So I am pasting here. The answer might be lengthy but it will definitely help you and others.
要获得方向/路径/路线,您需要谷歌地图方向API。我在我的应用程序中完成了它。所以我在这里粘贴。答案可能很长,但肯定会帮助你和其他人。
Write a class that parses Directions API response. Just copy and paste this code. Here is the snippet link as well.
编写一个解析Directions API响应的类。只需复制并粘贴此代码即可。这也是代码段链接。
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;
}
}
Get directions url. It will make complete URL to call api.
获取路线网址。它会生成完整的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;
}
Write a method that calls this url and gets response.
编写一个调用此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;
}
As this is the Network call, call it in separate thread:
由于这是网络调用,请在单独的线程中调用它:
/**
* 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);
}
}
And finally, see the onPostExecute()
method, it is calling ParserTask
, here it is:
最后,看到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);
}
}
Where lastPolyLine
is of com.google.android.gms.maps.model.Polyline
type.
lastPolyLine的位置是com.google.android.gms.maps.model.Polyline类型。
NOTE:
注意:
if (lastPolyLine != null) {
lastPolyLine.remove();
}
If you do not put this check, you will end up having multiple paths on every marker click.
如果您不进行此项检查,则每次单击标记时最终会有多个路径。
In your onMapReady()
method, set marker click listener and implement onMarkerClick()
:
在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;
}
#1
0
To get direction from one lat,lng location to another, you have to use Google direction api. For simplicity of parsing api response use google-maps-services-java library and draw polyline on Map. Following link is very help full for this https://android.jlelse.eu/google-maps-directions-api-5b2e11dee9b0
要从一个lat,lng位置到另一个位置获取方向,您必须使用Google方向api。为了简化解析api响应,请使用google-maps-services-java库并在Map上绘制折线。以下链接非常有用,请访问https://android.jlelse.eu/google-maps-directions-api-5b2e11dee9b0
#2
0
To get the direction/path/route, you need google maps directions API. I have done it in my app. So I am pasting here. The answer might be lengthy but it will definitely help you and others.
要获得方向/路径/路线,您需要谷歌地图方向API。我在我的应用程序中完成了它。所以我在这里粘贴。答案可能很长,但肯定会帮助你和其他人。
Write a class that parses Directions API response. Just copy and paste this code. Here is the snippet link as well.
编写一个解析Directions API响应的类。只需复制并粘贴此代码即可。这也是代码段链接。
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;
}
}
Get directions url. It will make complete URL to call api.
获取路线网址。它会生成完整的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;
}
Write a method that calls this url and gets response.
编写一个调用此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;
}
As this is the Network call, call it in separate thread:
由于这是网络调用,请在单独的线程中调用它:
/**
* 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);
}
}
And finally, see the onPostExecute()
method, it is calling ParserTask
, here it is:
最后,看到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);
}
}
Where lastPolyLine
is of com.google.android.gms.maps.model.Polyline
type.
lastPolyLine的位置是com.google.android.gms.maps.model.Polyline类型。
NOTE:
注意:
if (lastPolyLine != null) {
lastPolyLine.remove();
}
If you do not put this check, you will end up having multiple paths on every marker click.
如果您不进行此项检查,则每次单击标记时最终会有多个路径。
In your onMapReady()
method, set marker click listener and implement onMarkerClick()
:
在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;
}