I'm using the tutorial for mapbox and I can get geojson files to show just fine. But when trying to use a MultiLine geojson, I keep getting this exception and it doesn't show in my map.
Exception Loading GeoJSON: org.json.JSONException: Value [-84.38482011299999,44.24712923700008,0] at 1 of type org.json.JSONArray cannot be converted to double
I tried changing this line:
if (!TextUtils.isEmpty(type) && type.equalsIgnoreCase("LineString")) {
I changed "LineString" to "MultiLineString" and I still get the same exception. Everything else in my code is the same as tutorial as of right now.
I currently use osmdroid and I have no problems loading my geojson there, so I don't believe it's an issue with my file.
Trying to make the switch to mapbox.
public class MainActivity extends Activity implements OnMapReadyCallback
{
private static final String TAG = "DrawGeojsonLineActivity";
private MapView mapView;
private MapboxMap mapboxMap;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Mapbox.getInstance(this, "pk.eyJ1IjoiamViMTkyMDA0IiwiYSI6ImNpbWNyODZyaDAwMmZ1MWx2dHdzcHQ5M2EifQ.IZsMnB3wOYFIaX1A5sy7Mw");
// This contains the MapView in XML and needs to be called after the access token is configured.
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
#Override
public void onMapReady(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
// Load and Draw the GeoJSON
new DrawGeoJson().execute();
}
#Override
public void onResume() {
super.onResume();
mapView.onResume();
}
#Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
#Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
private class DrawGeoJson extends AsyncTask<Void, Void, List<LatLng>> {
#Override
protected List<LatLng> doInBackground(Void... voids) {
List<LatLng> points = new ArrayList<>();
try {
// Load GeoJSON file
InputStream inputStream = getAssets().open("st_helen_trail.geojson");
BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
inputStream.close();
// Parse JSON
JSONObject json = new JSONObject(sb.toString());
JSONArray features = json.getJSONArray("features");
JSONObject feature = features.getJSONObject(0);
JSONObject geometry = feature.getJSONObject("geometry");
if (geometry != null) {
String type = geometry.getString("type");
// Our GeoJSON only has one feature: a line string
if (!TextUtils.isEmpty(type) && type.equalsIgnoreCase("MultiLineString")) {
// Get the Coordinates
JSONArray coords = geometry.getJSONArray("coordinates");
for (int lc = 0; lc < coords.length(); lc++) {
JSONArray coord = coords.getJSONArray(lc);
LatLng latLng = new LatLng(coord.getDouble(1), coord.getDouble(0));
points.add(latLng);
}
}
}
} catch (Exception exception) {
Log.e(TAG, "Exception Loading GeoJSON: " + exception.toString());
}
return points;
}
#Override
protected void onPostExecute(List<LatLng> points) {
super.onPostExecute(points);
if (points.size() > 0) {
// Draw polyline on map
mapboxMap.addPolyline(new PolylineOptions()
.addAll(points)
.color(Color.parseColor("#3bb2d0"))
.width(2));
}
}
}
}
In your onPostExecute() method add this Code..
#Override
protected void onPostExecute(List<LatLng> points) {
super.onPostExecute(points);
if (points.size() > 0) {
LatLng[] dataOfArray = points.toArray(new LatLng[points.size()]);
// Draw polyline on map
mapboxMap.addPolyline(new PolylineOptions()
.addAll(dataOfArray)
.color(Color.parseColor("#3bb2d0"))
.width(2));
}
}
I figured this out about a week ago. This is what I got to work
I removed this:
new DrawGeoJson().execute();
And this:
private class DrawGeoJson extends AsyncTask<Void, Void, List<LatLng>> { #Override protected List<LatLng> doInBackground(Void... voids) { List<LatLng> points = new ArrayList<>(); try { // Load GeoJSON file InputStream inputStream = getAssets().open("st_helen_trail.geojson"); BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); StringBuilder sb = new StringBuilder(); int cp; while ((cp = rd.read()) != -1) { sb.append((char) cp); } inputStream.close(); // Parse JSON JSONObject json = new JSONObject(sb.toString()); JSONArray features = json.getJSONArray("features"); JSONObject feature = features.getJSONObject(0); JSONObject geometry = feature.getJSONObject("geometry"); if (geometry != null) { String type = geometry.getString("type"); // Our GeoJSON only has one feature: a line string if (!TextUtils.isEmpty(type) && type.equalsIgnoreCase("MultiLineString")) { // Get the Coordinates JSONArray coords = geometry.getJSONArray("coordinates"); for (int lc = 0; lc < coords.length(); lc++) { JSONArray coord = coords.getJSONArray(lc); LatLng latLng = new LatLng(coord.getDouble(1), coord.getDouble(0)); points.add(latLng); } } } } catch (Exception exception) { Log.e(TAG, "Exception Loading GeoJSON: " + exception.toString()); } return points; } #Override protected void onPostExecute(List<LatLng> points) { super.onPostExecute(points); if (points.size() > 0) { // Draw polyline on map mapboxMap.addPolyline(new PolylineOptions() .addAll(points) .color(Color.parseColor("#3bb2d0")) .width(2)); } }
Then added the code below inside the "onMapReady"
final AssetManager assetManager = getAssets();
try {
String[] imgPath = assetManager.list("mi_atv");
for (int i = 0; i< imgPath.length; i++) {
InputStream is1 = assetManager.open("mi_atv/" + imgPath[i]);
Log.d(TAG, imgPath[i]);
int size = is1.available();
byte[] buffer = new byte[size];
is1.read(buffer);
is1.close();
String json1 = new String(buffer, "UTF-8");
GeoJsonSource source = new GeoJsonSource(imgPath[i], json1);
map.addSource(source);
atv = new LineLayer(imgPath[i], imgPath[i]);
atv.setProperties(
lineColor(Color.parseColor("#7fff00")),
lineWidth(1.0f)
);
map.addLayer(main.atv);
}
}
catch (Exception exception) {
Log.e(TAG, "Exception Loading GeoJSON: " + exception.toString());
}
The problem is that in case of multilinestring you have an extra array to get.
MULTILINESTRING example:
coordinates": [ [ [ 7.38588715, 44.17675579 ], [ 7.385923192, 44.176754868 ],...
LINESTRING example:
coordinates": [ [ 7.38588715, 44.17675579 ], [ 7.385923192, 44.176754868 ],...
so:
//replace linestring with multilinestring:
if (!TextUtils.isEmpty(type) && type.equalsIgnoreCase("MultiLineString")) {
// get extra array adding .getJSONArray(0)
JSONArray coords = geometry.getJSONArray("coordinates").getJSONArray(0);
for (int lc = 0; lc < coords.length(); lc++) {
Related
I will be posting all of my codes here and a sample output of my project. I have set the alternative to yes to display the alternate routes but problem is, how do I parse all the distance from all routes? It only gets the distance of the main route but not the alternate routes. How do I change my Parse java class to get all the directions in alternate routes and display it?
public class ThirdFragment extends Fragment implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
LocationListener,DirectionFinderListener,AdapterView.OnItemClickListener {
/**************************************************************/
// private GoogleMap mMap;
private ImageButton btnFindPath;
private AutoCompleteTextView etOrigin;
private AutoCompleteTextView etDestination;
private List<Marker> originMarkers = new ArrayList<>();
private List<Marker> destinationMarkers = new ArrayList<>();
private List<Polyline> polylinePaths = new ArrayList<>();
private ProgressDialog progressDialog;
private static final String LOG_TAG = "Google Places Autocomplete";
private static final String PLACES_API_BASE = "https://maps.googleapis.com/maps/api/place";
private static final String TYPE_AUTOCOMPLETE = "/autocomplete";
private static final String OUT_JSON = "/json";
private static final String API_KEY = "MY API KEY HERE";
//FOR COLLAPSING TOOLBAR
private CollapsingToolbarLayout collapsingToolbarLayout = null;
/**************************************************************************************************************/
double latitude;
double longitude;
GoogleMap mMap;
MapView mapView;
View Myview;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
LocationRequest mLocationRequest;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Myview = inflater.inflate(R.layout.activity_third_fragment, container, false);
mapView = (MapView) Myview.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
/********************************************************************/
collapsingToolbarLayout = (CollapsingToolbarLayout) Myview.findViewById(R.id.collapsing_toolbar);
/****************************************************************************************/
btnFindPath = (ImageButton) Myview.findViewById(R.id.btnFindPath);
etOrigin = (AutoCompleteTextView) Myview.findViewById(R.id.etOrigin);
etDestination = (AutoCompleteTextView) Myview.findViewById(R.id.etDestination);
btnFindPath.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendRequest();
}
});
etOrigin.setAdapter(new GooglePlacesAutocompleteAdapter(getActivity(), R.layout.list_item));
etOrigin.setOnItemClickListener(this);
etDestination.setAdapter(new GooglePlacesAutocompleteAdapter(getActivity(), R.layout.list_item));
etDestination.setOnItemClickListener(this);
return Myview;
}
//**********For changing colors in the directions************************************************************/
/**************************************************************************************************************/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
goToLocationZoom(9.3068, 123.3054, 15);
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//Initialize Google Play Services
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
} else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
LatLngBounds Dumaguete = new LatLngBounds(new LatLng(9.267, 123.264), new LatLng(9.33, 123.311));
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mMap.setMinZoomPreference(15.0f);
mMap.setMaxZoomPreference(20.0f);
mMap.setLatLngBoundsForCameraTarget(Dumaguete);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Dumaguete.getCenter(), 15));
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mMap.setMyLocationEnabled(true);
}
private void goToLocationZoom(double lat, double lng, int zoom) {
LatLng ll = new LatLng(lat, lng);
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(ll, zoom);
mMap.moveCamera(update);
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(getActivity(),
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) {
}
#Override
public void onLocationChanged(Location location) {
Log.d("onLocationChanged", "entered");
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
latitude = location.getLatitude();
longitude = location.getLongitude();
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
//mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
Toast.makeText(getActivity(),"Your Current Location", Toast.LENGTH_LONG).show();
Log.d("onLocationChanged", String.format("latitude:%.3f longitude:%.3f",latitude,longitude));
//stop location updates
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
Log.d("onLocationChanged", "Removing Location Updates");
}
Log.d("onLocationChanged", "Exit");
}
private void sendRequest() {
String origin = etOrigin.getText().toString();
String destination = etDestination.getText().toString();
if (origin.isEmpty()) {
Toast.makeText(getActivity(), "Please enter origin address!", Toast.LENGTH_SHORT).show();
return;
}
if (destination.isEmpty()) {
Toast.makeText(getActivity(), "Please enter destination address!", Toast.LENGTH_SHORT).show();
return;
}
try {
new DirectionFinder(this, origin, destination).execute();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
#Override
public void onDirectionFinderStart() {
progressDialog = ProgressDialog.show(getActivity(), "Please wait.",
"Finding direction..!", true);
if (originMarkers != null) {
for (Marker marker : originMarkers) {
marker.remove();
}
}
if (destinationMarkers != null) {
for (Marker marker : destinationMarkers) {
marker.remove();
}
}
if (polylinePaths != null) {
for (Polyline polyline : polylinePaths) {
polyline.remove();
}
}
}
#Override
public void onDirectionFinderSuccess(List<Route> routes) {
progressDialog.dismiss();
polylinePaths = new ArrayList<>();
originMarkers = new ArrayList<>();
destinationMarkers = new ArrayList<>();
Toast.makeText(getActivity(), "Directions found!", Toast.LENGTH_SHORT).show();
for (final Route route : routes) {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(route.startLocation, 16));
((TextView) Myview.findViewById(R.id.tvDistance)).setText(route.distance.text); //For Distance
originMarkers.add(mMap.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.fromResource(R.drawable.start_blue))
.title(route.startAddress)
.position(route.startLocation)));
destinationMarkers.add(mMap.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green))
.title(route.endAddress)
.position(route.endLocation)));
/******************For Changing color ********************************************************/
mMap.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener() {
#Override
public void onPolylineClick(Polyline polyline) {
// Flip the values of the red, green and blue components of the polyline's color.
polyline.setColor(polyline.getColor() ^ 0x00ffffff);
// Toast.makeText(getActivity(), "Hello", Toast.LENGTH_SHORT).show();
}
});
/*************************************************************************************************/
Random rnd = new Random();
int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(257), rnd.nextInt(258));
/**/
PolylineOptions polylineOptions = new PolylineOptions().
geodesic(true).color(color).width(15).clickable(true);
for (int i = 0; i < route.points.size(); i++)
polylineOptions.add(route.points.get(i));
polylinePaths.add(mMap.addPolyline(polylineOptions));
}
}
public void onItemClick(AdapterView adapterView, View view, int position, long id) {
String str = (String) adapterView.getItemAtPosition(position);
Toast.makeText(getActivity(), str, Toast.LENGTH_SHORT).show();
}
public static ArrayList autocomplete(String input) {
ArrayList resultList = null;
HttpURLConnection conn = null;
StringBuilder jsonResults = new StringBuilder();
try {
StringBuilder sb = new StringBuilder(PLACES_API_BASE + TYPE_AUTOCOMPLETE + OUT_JSON);
sb.append("?key=" + API_KEY);
sb.append("&types=establishment&strictbounds&location=9.30684,123.305447&radius=2000");
sb.append("&input=" + URLEncoder.encode(input, "utf8"));
URL url = new URL(sb.toString());
conn = (HttpURLConnection) url.openConnection();
InputStreamReader in = new InputStreamReader(conn.getInputStream());
// Load the results into a StringBuilder
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
jsonResults.append(buff, 0, read);
}
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "Error processing Places API URL", e);
return resultList;
} catch (IOException e) {
Log.e(LOG_TAG, "Error connecting to Places API", e);
return resultList;
} finally {
if (conn != null) {
conn.disconnect();
}
}
try {
// Create a JSON object hierarchy from the results
JSONObject jsonObj = new JSONObject(jsonResults.toString());
JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");
// Extract the Place descriptions from the results
resultList = new ArrayList(predsJsonArray.length());
for (int i = 0; i < predsJsonArray.length(); i++) {
System.out.println(predsJsonArray.getJSONObject(i).getString("description"));
System.out.println("============================================================");
resultList.add(predsJsonArray.getJSONObject(i).getString("description"));
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Cannot process JSON results", e);
}
return resultList;
}
class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable {
private ArrayList resultList;
public GooglePlacesAutocompleteAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
#Override
public int getCount() {
return resultList.size();
}
#Override
public String getItem(int index) {
return String.valueOf(resultList.get(index));
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
// Retrieve the autocomplete results.
resultList = autocomplete(constraint.toString());
// Assign the data to the FilterResults
filterResults.values = resultList;
filterResults.count = resultList.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
return filter;
}
}
#Override
public void onResume() {
mapView.onResume();
super.onResume();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
// mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}//End of CLass ThirdFragment.java
This is my Data Parsing and how do I change it to also get the distance of the alternate routes?
DirectionFInder.java
import android.os.AsyncTask;
import com.google.android.gms.maps.model.LatLng;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
public class DirectionFinder {
private static final String DIRECTION_URL_API = "https://maps.googleapis.com/maps/api/directions/json?";
private static final String GOOGLE_API_KEY = "AIzaSyC1E8NU2jjoQF7dN37bIOz_1fy0fe98YhI";
private DirectionFinderListener listener;
private String origin;
private String destination;
public DirectionFinder(DirectionFinderListener listener, String origin, String destination) {
this.listener = listener;
this.origin = origin;
this.destination = destination;
}
public void execute() throws UnsupportedEncodingException {
listener.onDirectionFinderStart();
new DownloadRawData().execute(createUrl());
}
private String createUrl() throws UnsupportedEncodingException {
String urlOrigin = URLEncoder.encode(origin, "utf-8");
String urlDestination = URLEncoder.encode(destination, "utf-8");
return DIRECTION_URL_API + "origin=" + urlOrigin + "&destination=" + urlDestination +"&alternatives=true" +"&key=" + GOOGLE_API_KEY;
}
private class DownloadRawData extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String link = params[0];
try {
URL url = new URL(link);
InputStream is = url.openConnection().getInputStream();
StringBuffer buffer = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String res) {
try {
parseJSon(res);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void parseJSon(String data) throws JSONException {
if (data == null)
return;
List<Route> routes = new ArrayList<Route>();
JSONObject jsonData = new JSONObject(data);
JSONArray jsonRoutes = jsonData.getJSONArray("routes");
for (int i = 0; i < jsonRoutes.length(); i++) {
JSONObject jsonRoute = jsonRoutes.getJSONObject(i);
Route route = new Route();
JSONObject overview_polylineJson = jsonRoute.getJSONObject("overview_polyline");
JSONArray jsonLegs = jsonRoute.getJSONArray("legs");
JSONObject jsonLeg = jsonLegs.getJSONObject(0);
JSONObject jsonDistance = jsonLeg.getJSONObject("distance");
JSONObject jsonDuration = jsonLeg.getJSONObject("duration");
JSONObject jsonEndLocation = jsonLeg.getJSONObject("end_location");
JSONObject jsonStartLocation = jsonLeg.getJSONObject("start_location");
route.distance = new Distance(jsonDistance.getString("text"), jsonDistance.getInt("value"));
route.duration = new Duration(jsonDuration.getString("text"), jsonDuration.getInt("value"));
route.endAddress = jsonLeg.getString("end_address");
route.startAddress = jsonLeg.getString("start_address");
route.startLocation = new LatLng(jsonStartLocation.getDouble("lat"), jsonStartLocation.getDouble("lng"));
route.endLocation = new LatLng(jsonEndLocation.getDouble("lat"), jsonEndLocation.getDouble("lng"));
route.points = decodePolyLine(overview_polylineJson.getString("points"));
routes.add(route);
}
listener.onDirectionFinderSuccess(routes);
}
private List<LatLng> decodePolyLine(final String poly) {
int len = poly.length();
int index = 0;
List<LatLng> decoded = new ArrayList<LatLng>();
int lat = 0;
int lng = 0;
while (index < len) {
int b;
int shift = 0;
int result = 0;
do {
b = poly.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 = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
decoded.add(new LatLng(
lat / 100000d, lng / 100000d
));
}
return decoded;
}
}
This is the screenshot of the application.
The dark green color is the main route and the pink and blue are the alternate routes. How can I get the distance of the pink and blue as well? Please help.
You are already looping through all of the routes, so storing the distance for each route should be simple. This line of code is where you get the distance for each route:
route.distance = new Distance(jsonDistance.getString("text"), jsonDistance.getInt("value"));'
If you create an array, you can store the value of each route during each iteration of the loop. Let's say you have an array called routeDistances[]. You could do something like this:
for (int i = 0; i < jsonRoutes.length(); i++) {
JSONObject jsonRoute = jsonRoutes.getJSONObject(i);
Route route = new Route();
JSONObject overview_polylineJson = jsonRoute.getJSONObject("overview_polyline");
JSONArray jsonLegs = jsonRoute.getJSONArray("legs");
JSONObject jsonLeg = jsonLegs.getJSONObject(0);
JSONObject jsonDistance = jsonLeg.getJSONObject("distance");
JSONObject jsonDuration = jsonLeg.getJSONObject("duration");
JSONObject jsonEndLocation = jsonLeg.getJSONObject("end_location");
JSONObject jsonStartLocation = jsonLeg.getJSONObject("start_location");
routeDistances[i] = jsonDistance.getInt("value"); // add this line
route.distance = new Distance(jsonDistance.getString("text"), jsonDistance.getInt("value"));
route.duration = new Duration(jsonDuration.getString("text"), jsonDuration.getInt("value"));
route.endAddress = jsonLeg.getString("end_address");
route.startAddress = jsonLeg.getString("start_address");
route.startLocation = new LatLng(jsonStartLocation.getDouble("lat"), jsonStartLocation.getDouble("lng"));
route.endLocation = new LatLng(jsonEndLocation.getDouble("lat"), jsonEndLocation.getDouble("lng"));
route.points = decodePolyLine(overview_polylineJson.getString("points"));
routes.add(route);
}
The line of code will allow you to store the distance for each route. You can then get the distance using the array. For example routeDistances[0] will have the distance for the first route, routeDistances[1] will have the distance for the next route etc.
I have spent days on this, but I can't find a solution to my problem:
I'm developing an app that retrieves a list of theaters showing some movie selected by the user, parsing an HTML page in an AsyncTask.
I want to visualize those theaters on a Map with markers, so I need coordinates: once the "GetCinemaList" AsyncTask is completed, I try to populate my markerList in onPostExecute.
I have an SQLite db in which I store [theater|city|lat|lng]. So I first look up in the db, if it is not found I want call another AsyncTask to retrieve coordinates from HTTP google geocoding ('cause device geocoder returns null, causing the app to crash)
The problem is I am not able to return the LatLng point to the first AsyncTask...
I have tried to use listeners and to override processFinish(LatLng p), but I can't assign the value to my variable cause, accessing it from inner class it should be final.
Any help/idea? Thanks!
Here my code (containing error) for the AsyncTasks , in my Activity.
private class GetCinemaList extends AsyncTask<URL, Void, List<String>> {
private Context mContext;
public GetCinemaList(Context c){
mContext = c;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected List<String> doInBackground(URL... urls) {
List<String> cinemas = new ArrayList<>();
Document docHTML = null;
try {
docHTML = QueryUtils.makeRequest(urls[0]);
cinemas = QueryUtils.extractCinemasFromHTML(mTitile, docHTML);
} catch (IOException e) {
Log.e("JSwa", "Problem making request for parsing HTML "+e);
}
return cinemas;
}
#Override
protected void onPostExecute(List<String> result) {
super.onPostExecute(result);
cinemaList = result;
LatLng point;
pointList = new ArrayList<>();
for (String elem : cinemaList) {
String name = elem.split("\t")[0];
String orari = elem.split("\t")[1];
Cursor cursor = queryDB(mCinemaDbR, city, name);
if (!cursor.moveToFirst()) {
// call geocoding service
new LatLongFromService(name.concat(" " + city), new AsyncResponse() {
#Override
public void processFinish(LatLng output) {
point = output;
}
}).execute();
Log.d("JSwa", "Inserting point "+point.toString());
// insert new value in the database
long id = addCimena(mCinemaDbW, name, city, String.valueOf(point.latitude), String.valueOf(point.longitude));
// insert new value in the list
MarkerOptions marker = new MarkerOptions().position(point).title(name).snippet(orari);
pointList.add(marker);
}
else{
double lat = Double.parseDouble(cursor.getString(cursor.getColumnIndex(CinemaEntry.COLUMN_LAT)));
double lng = Double.parseDouble(cursor.getString(cursor.getColumnIndex(CinemaEntry.COLUMN_LNG)));
MarkerOptions marker = new MarkerOptions().position(new LatLng(lat,lng)).title(name)
.snippet(orari);
pointList.add(marker);
}
cursor.close();
}
for (MarkerOptions marker : pointList){
m_map.addMarker(marker);
}
}
}
// Sometimes happens that device gives location = null
public class LatLongFromService extends AsyncTask<Void, Void, StringBuilder> {
String place;
public AsyncResponse delegate = null;
public LatLongFromService(String place, AsyncResponse resp) {
this.place = place;
delegate = resp;
}
#Override
protected StringBuilder doInBackground(Void... params) {
try {
HttpURLConnection conn = null;
StringBuilder jsonResults = new StringBuilder();
String googleMapUrl = "http://maps.googleapis.com/maps/api/geocode/json?address=" + this.place + "&sensor=false";
URL url = new URL(googleMapUrl);
conn = (HttpURLConnection) url.openConnection();
InputStreamReader in = new InputStreamReader(
conn.getInputStream());
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
jsonResults.append(buff, 0, read);
}
return jsonResults;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(StringBuilder result) {
super.onPostExecute(result);
try {
JSONObject jsonObj = new JSONObject(result.toString());
JSONArray resultJsonArray = jsonObj.getJSONArray("results");
JSONObject location = resultJsonArray
.getJSONObject(0).getJSONObject("geometry").getJSONObject("location");
String lat_helper = location.getString("lat");
double lat = Double.valueOf(lat_helper);
String lng_helper = location.getString("lng");
double lng = Double.valueOf(lng_helper);
delegate.processFinish(new LatLng(lat, lng));
} catch (JSONException e) {
e.printStackTrace();
}
}
}`
I am using AsyncTask to run information to and from my online mySQL database. I am then using JSON parsing to add the information from the database as a marker on my MapBox map. Currently when a user uploads a new marker (washroom in the code) it uploads the information to the database, then runs the onPostExecute method and goes back to the MapsActivity.java. MapsActivity.java should reload the map and display the newly added marker but it doesn't; it only displays the markers that where added before adding the new one. If you close and open the app the markers are updated, displaying all the markers including the new one! Any help would be appreciated!
Part of MapsActivity.java
public class MapsActivity extends FragmentActivity {
private MapView mapView;
private MapboxMap map;
private ImageButton locationToggle;
private LocationServices locationServices;
private String json_string;
private JSONObject jsonObject;
private JSONArray jsonArray;
public static String WASHROOMINFO;
public static String CURRENT_LOCATION;
private static final int PERMISSIONS_LOCATION = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MapboxAccountManager.start(this, getString(R.string.accessToken));
setContentView(R.layout.activity_maps);
//getting location services
locationServices = com.mapbox.mapboxsdk.location.LocationServices.getLocationServices(MapsActivity.this);
//onClick to go to add washroom activity
findViewById(R.id.addWashroom).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (CURRENT_LOCATION != null) {
Intent intent = new Intent(getBaseContext(), AddWashroom.class);
startActivity(intent);
} else {
Toast.makeText(getBaseContext(),"You Must Turn on User Location Before Adding a Washroom!",Toast.LENGTH_LONG).show();
}
}
});
//washrooms have not been loaded in yet
if (!BackgroundTask.WASHROOMS_LOADED) {
//getting database info
String method = "getWashroom";
BackgroundTask backgroundTask = new BackgroundTask(getBaseContext());
backgroundTask.execute(method);
finish();
}
mapView = (MapView) findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(MapboxMap mapboxMap) {
//when map is ready assign mapboxMap variable
map = mapboxMap;
//Washroom loading has been requested and JSON data is ready
if (BackgroundTask.WASHROOMS_LOADED) {
//Getting JSON data from intent
json_string = getIntent().getExtras().getString("json_data");
try {
//new JSON object from JSON data
jsonObject = new JSONObject(json_string);
//gets JSON array from JSON object
jsonArray = jsonObject.getJSONArray("server_response");
//Marker list for buffering markers
List<Marker> markers = new ArrayList<Marker>();
//do this for all markers!
for (int i = 0; i < jsonArray.length(); i++) {
//Single JSON object of single marker
JSONObject JO = jsonArray.getJSONObject(i);
//Dividing location field into lat & lng
String latlng = JO.getString("location");
String[] latlngSplit = latlng.split(" , ",2);
double lat = Double.valueOf(latlngSplit[0]);
double lng = Double.valueOf(latlngSplit[1]);
//adding marker
Marker marker = map.addMarker(new MarkerOptions()
.title(JO.getString("name"))
.setSnippet(JO.getString("price"))
.position(new LatLng(lat,lng))
);
//add marker to markers list.
markers.add(marker);
}
BackgroundTask.WASHROOMS_LOADED = false;
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
locationToggle = (ImageButton) findViewById(R.id.location_toggle);
locationToggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (map != null) {
//toggle GPS when clicking show location button
toggleGps(!map.isMyLocationEnabled());
}
}
});
}
BackgroundTask (AsyncTask)
class BackgroundTask extends AsyncTask<String, Void, String> {
Context ctx;
public static boolean WASHROOMS_LOADED;
private String JSON_STRING;
private String json_string;
BackgroundTask(Context ctx) {
this.ctx = ctx.getApplicationContext();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
String add_url = "http://appart-software.com/add_washroom.php";
String get_url = "http://appart-software.com/get_washroom.php";
#Override
protected String doInBackground(String... params) {
String method = params[0];
if (method.equals("addWashroom")) {
String location = params[1];
String name = params[2];
String price = params[3];
try {
URL url = new URL(add_url);
HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setDoOutput(true);
OutputStream outputStream = httpUrlConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream,"UTF-8"));
String data_string = URLEncoder.encode("WClocation","UTF-8")+"="+URLEncoder.encode(location,"UTF-8")+"&"+
URLEncoder.encode("WCname","UTF-8")+"="+URLEncoder.encode(name,"UTF-8")+"&"+
URLEncoder.encode("WCprice","UTF-8")+"="+URLEncoder.encode(price,"UTF-8");
bufferedWriter.write(data_string);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
InputStream inputStream = httpUrlConnection.getInputStream();
inputStream.close();
httpUrlConnection.disconnect();
return "Washroom Added!";
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//You want to get washroom info
} else if (method.equals("getWashroom")){
try {
URL url = new URL(get_url);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"iso-8859-1"));
StringBuilder stringBuilder = new StringBuilder();
while ((JSON_STRING = bufferedReader.readLine())!=null) {
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
//Return JSON formatted info
return stringBuilder.toString().trim();
} catch (MalformedURLException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
if (result.equals("Washroom Added!")) {
Toast.makeText(ctx,result,Toast.LENGTH_LONG).show();
WASHROOMS_LOADED = false;
} else {
//setting result as a movable string
json_string = result;
//intent and sending JSON data
Intent intent = new Intent(ctx,MapsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("json_data",json_string);
ctx.startActivity(intent);
WASHROOMS_LOADED = true;
}
}
}
If you need anymore of my code, I would be happy to show some more.
You are getting new marker on reopening the app because you are getting database info in your onCreate() method which is triggered only on start of activity. Try getting database info either when location changes or try overriding onNewIntent method. To override onNewIntent first set launchmode of your activity to singleTop in manifest.
i am running a web service with some json data which i use to make markers on my map(this gets updated every hour).i want to add button on my android map so that i will refresh the markers data.any idea without changing much of the structure?should i do something on the threads?or restart the activity?
heres is the code
public class MainActivity extends FragmentActivity {
private static final String LOG_TAG = "jsonmap";
private static final String SERVICE_URL = "http://7a27183e.ngrok.com";
public GoogleMap map;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_maps);
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (map == null) {
MapFragment mapFragment = (MapFragment) getFragmentManager()
.findFragmentById(R.id.map);
map = mapFragment.getMap();
if (map != null) {
setUpMap();
// new MarkerTask().execute();
}
}
}
private void setUpMap() {
UiSettings settings = map.getUiSettings();
settings.setZoomControlsEnabled(true);
settings.setScrollGesturesEnabled(true);
// Retrieve the city data from the web service
// In a worker thread since it's a network operation.
new Thread(new Runnable() {
public void run() {
try {
retrieveAndAddCities();
} catch (IOException e) {
Log.e(LOG_TAG, "Cannot retrive cities", e);
return;
}
}
}).start();
}
protected void retrieveAndAddCities() throws IOException {
HttpURLConnection conn = null;
final StringBuilder json = new StringBuilder();
try {
// Connect to the web service
URL url = new URL(SERVICE_URL);
conn = (HttpURLConnection) url.openConnection();
InputStreamReader in = new InputStreamReader(conn.getInputStream());
// Read the JSON data into the StringBuilder
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
json.append(buff, 0, read);
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error connecting to service", e);
throw new IOException("Error connecting to service", e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
// Create markers for the city data.
// Must run this on the UI thread since it's a UI operation.
runOnUiThread(new Runnable() {
public void run() {
try {
createMarkersFromJson(json.toString());
} catch (JSONException e) {
Log.e(LOG_TAG, "Error processing JSON", e);
}
}
});
}
void createMarkersFromJson(String json) throws JSONException {
// De-serialize the JSON string into an array of city objects
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
// Create a marker for each city in the JSON data.
//.title(jsonObj.getString("pollutant")+" "+jsonObj.getString("network"))
// .snippet(Integer.toString(jsonObj.getInt("numeric_val")))
//DATE!!
JSONObject jsonObj = jsonArray.getJSONObject(i);
map.addMarker(new MarkerOptions()
.title(jsonObj.getString("network") + "\n" + jsonObj.getString("date"))
.snippet(jsonObj.getString("pollutant") + "=" + jsonObj.getString("numeric_val"))
.position(new LatLng(
jsonObj.getDouble("x"),
jsonObj.getDouble("y")))
.icon(BitmapDescriptorFactory.defaultMarker(new Random().nextInt(360)))
);
map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoContents(Marker arg0) {
return null;
}
#Override
public View getInfoWindow(Marker arg0) {
View v = getLayoutInflater().inflate(R.layout.customlayout, null);
TextView tTitle = (TextView) v.findViewById(R.id.title);
TextView tSnippet = (TextView) v.findViewById(R.id.snippet);
tTitle.setText(arg0.getTitle());
tSnippet.setText(arg0.getSnippet());
return v;
}
});
}
}
}
this is the json structure:
https://gist.githubusercontent.com/anonymous/42af315ab003ab01764d/raw/79b6cf5451038bd2e35c376766e9ab44bd385a02/gistfile2.txt
and a screenshot:
http://imgur.com/WZNC9Oz
I have done some modification in your method named createMarkersFromJson() at line map.addMarker(). Now you can use changeMarkerPosition() to change the position of marker.
HashMap<String, Marker> markerHashMap = new HashMap<>();
void changeMarkerPosition(String key, LatLng latLng) {
markerHashMap.get(key).setPosition(latLng);
}
void createMarkersFromJson(String json) throws JSONException {
// De-serialize the JSON string into an array of city objects
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
// Create a marker for each city in the JSON data.
//.title(jsonObj.getString("pollutant")+" "+jsonObj.getString("network"))
// .snippet(Integer.toString(jsonObj.getInt("numeric_val")))
//DATE!!
JSONObject jsonObj = jsonArray.getJSONObject(i);
markerHashMap.put("key"+i,(map.addMarker(new MarkerOptions()
.title(jsonObj.getString("network") + "\n" + jsonObj.getString("date"))
.snippet(jsonObj.getString("pollutant") + "=" + jsonObj.getString("numeric_val"))
.position(new LatLng(
jsonObj.getDouble("x"),
jsonObj.getDouble("y")))
.icon(BitmapDescriptorFactory.defaultMarker(new Random().nextInt(360)))
);)
map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoContents(Marker arg0) {
return null;
}
#Override
public View getInfoWindow(Marker arg0) {
View v = getLayoutInflater().inflate(R.layout.customlayout, null);
TextView tTitle = (TextView) v.findViewById(R.id.title);
TextView tSnippet = (TextView) v.findViewById(R.id.snippet);
tTitle.setText(arg0.getTitle());
tSnippet.setText(arg0.getSnippet());
return v;
}
});
}
I'm populating a Google map with markers, I don't get errors and my variables are getting their values but it isnt populating any markers. It just show one marker and it is my current location.
here is the code that i call when populating:
private void showData() {
int count = users.length();
for(;i<=count;i++) {
try {
JSONObject jsonObject = users.getJSONObject(i);
maplat = Double.parseDouble(jsonObject.getString(lat));
maplng = Double.parseDouble(jsonObject.getString(lng));
MarkerOptions marker = new MarkerOptions().position(new LatLng(maplat, maplng)).title("Hello Maps");
marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.pin));
googleMap.addMarker(marker);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
My whole code:
public class MapActivity extends AppCompatActivity{
private GoogleMap googleMap;
double curLat;
double curLng;
double maplat;
double maplng;
private static final String JSON_ARRAY = "result";
private static final String lat= "lat";
private static final String lng = "lng";
private JSONArray users = null;
private String q;
private static final String GET_URL = "http://testevent.site88.net/getlocation.php";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
GPSTracker gps = new GPSTracker(this);
curLat = gps.getLatitude();
curLng = gps.getLongitude();
try {
// Loading map
initilizeMap();
} catch (Exception e) {
e.printStackTrace();
}
}
private void extractJSON(){
try {
JSONObject jsonObject = new JSONObject(q);
users = jsonObject.getJSONArray(JSON_ARRAY);
} catch (JSONException e) {
e.printStackTrace();
}
}
private void showData() {
int count = users.length();
for(int i = 0;i<=count;i++) {
try {
JSONObject jsonObject = users.getJSONObject(i);
maplat = Double.parseDouble(jsonObject.getString(lat));
maplng = Double.parseDouble(jsonObject.getString(lng));
MarkerOptions marker = new MarkerOptions().position(new LatLng(maplat, maplng)).title("Hello Maps");
marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.pin));
googleMap.addMarker(marker);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void getJSON(String url) {
class GetJSON extends AsyncTask<String, Void, String>{
ProgressDialog loading;
#Override
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(MapActivity.this, "Please Wait...",null,true,true);
}
#Override
protected String doInBackground(String... params) {
String uri = params[0];
BufferedReader bufferedReader = null;
try {
URL url = new URL(uri);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
StringBuilder sb = new StringBuilder();
bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String json;
while((json = bufferedReader.readLine())!= null){
sb.append(json+"\n");
}
return sb.toString().trim();
}catch(Exception e){
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
loading.dismiss();
q=s;
extractJSON();
showData();
MarkerOptions marker = new MarkerOptions().position(new LatLng(curLat, curLng)).title("Hello Maps");
// Changing marker icon
marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.pin));
// adding marker
googleMap.addMarker(marker);
}
}
GetJSON gj = new GetJSON();
gj.execute(url);
}
private void initilizeMap() {
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
// check if map is created successfully or not
if (googleMap == null) {
Toast.makeText(getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
}
getJSON(GET_URL);
}
#Override
protected void onResume() {
super.onResume();
initilizeMap();
}
}