The following code works but is slow and I know can be better, just don't understand how to make it work. The end result is displaying the actual driving distance from the users current location to multiple locations (I'm only including two end locations here to try and save space). This way they can see which location is actually closer to where they currently are. Right now I'm making multiple calls when I know I should be able to pass in everything at once.
In Locations.java
, in getLastLocation()
I'm calling both FirstDownloadTask
and SecondDownloadTask
in order to set the text to the correct TextView
for the destination location being passed in. How can I change this so I only have one DownloadTask
and ParserTask
and when I call DownloadTask
be able to pass in more than one URL? (ex: firstDownloadTask.execute(url1, url2)
) Since ParserTask
processes one JSON string, how can I modify this so that it tells ParserTask
the correct TextView
to set based on the String url
being processed?
When I try to pass in multiple parameters, it sets the text of each TextView
to the distance of the end location that was passed in last. I can't figure out how to tell it to process the first distance and set the first TextView
and move on to the next and so on. Like I said, it does currently work, just not as good as it could.
Update
Still trying to get it working, following along with the short example seen on the Android Developers site.
Update 2
I merged the two AsyncTask
classes (FirstDownloadTask
and SecondDownloadTask
merged to DownloadTask
) and am passing in both destination URLs. I also moved declaring the TextViews
into onPostExecute
, trying to pass them in individually along with the URL. I updated the Locations.java
below, commenting out what I removed and adding the new class.
Now when I run it but get the LogCat error:
Cannot execute task: the task is already running
LogCat
08-07 08:56:29.378: E/AndroidRuntime(13918): FATAL EXCEPTION: main
08-07 08:56:29.378: E/AndroidRuntime(13918): java.lang.IllegalStateException: Cannot execute task: the task is already running.
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:575)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.AsyncTask.execute(AsyncTask.java:534)
08-07 08:56:29.378: E/AndroidRuntime(13918): at com.android.project.Locations$DownloadTask.onPostExecute(Locations.java:270)
08-07 08:56:29.378: E/AndroidRuntime(13918): at com.android.project.Locations$DownloadTask.onPostExecute(Locations.java:1)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.AsyncTask.finish(AsyncTask.java:631)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.AsyncTask.access$600(AsyncTask.java:177)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.Handler.dispatchMessage(Handler.java:99)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.os.Looper.loop(Looper.java:137)
08-07 08:56:29.378: E/AndroidRuntime(13918): at android.app.ActivityThread.main(ActivityThread.java:5059)
08-07 08:56:29.378: E/AndroidRuntime(13918): at java.lang.reflect.Method.invokeNative(Native Method)
08-07 08:56:29.378: E/AndroidRuntime(13918): at java.lang.reflect.Method.invoke(Method.java:511)
08-07 08:56:29.378: E/AndroidRuntime(13918): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
08-07 08:56:29.378: E/AndroidRuntime(13918): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:555)
08-07 08:56:29.378: E/AndroidRuntime(13918): at dalvik.system.NativeStart.main(Native Method)
Locations.java
private Location currentLocation = null;
private LocationManager locationManager;
private GeoPoint currentPoint;
ArrayList<LatLng> markerPoints;
public class Locations extends Fragment {
// onCreate, onActivityCreated
public void getLastLocation() {
String provider = getBestProvider();
currentLocation = locationManager.getLastKnownLocation(provider);
if (currentLocation != null) { setCurrentLocation(currentLocation); }
this.markerPoints = new ArrayList<LatLng>();
// Get current position
LatLng fromLocation = new LatLng(currentLocation.getLatitude(),
currentLocation.getLongitude());
// Set destination locations
LatLng dest1 = new LatLng(35.5158335, -82.7046222);
LatLng dest2 = new LatLng(35.4533462, -82.3823722);
Locations.this.markerPoints.add(fromLocation);
Locations.this.markerPoints.add(dest1);
Locations.this.markerPoints.add(dest2);
String url1 = Locations.this.getDirectionsUrl(fromLocation, dest1);
String url2 = Locations.this.getDirectionsUrl(fromLocation, dest2);
new DownloadTask().execute(url1, url2); // Passing in both url1 and url2 now
/* FirstDownloadTask firstDownloadTask = new FirstDownloadTask();
SecondDownloadTask secondDownloadTask = new SecondDownloadTask();
// Start downloading json data from Google Directions API
firstDownloadTask.execute(url1);
secondDownloadTask.execute(url2); */
}
private String getDirectionsUrl(LatLng origin, LatLng dest) {
String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
String sensor = "sensor=false";
String parameters = str_origin + "&" + str_dest + "&" + sensor;
String output = "json";
String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
return url;
}
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) { sb.append(line); }
data = sb.toString();
br.close();
} catch (Exception e) {
Log.d("Exception while downloading url", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
// Changed FirstDownloadTask and SecondDownloadTask to:
private class DownloadTask extends AsyncTask<String, Void, ArrayList<String>> {
@Override
protected ArrayList<String> doInBackground(String... urlList) {
try {
ArrayList<String> returnList = new ArrayList<String>();
for (String url : urlList) {
String data = Locations.this.downloadUrl(url);
returnList.add(data);
if (isCancelled()) break;
}
return returnList;
} catch (Exception e) {
Log.d("Background Task", e.toString());
return null; // Failed, return null
}
}
@Override
protected void onPostExecute(ArrayList<String> results) {
super.onPostExecute(results);
TextView tv1 = (TextView) getActivity().findViewById(R.id.textView1);
TextView tv2 = (TextView) getActivity().findViewById(R.id.textView2);
TextView[] views = { tv1, tv2 };
ParserTask parserTask = new ParserTask();
int i = 0;
for (String url : results) { // Trying to execute url1 and set tv1 first then execute url2 and set tv2 second
parserTask.execute(url); // Trying to execute correct url
parserTask.setTextView(views[i]); // Trying to set text to correct TextView
i++;
}
}
}
private class ParserTask extends AsyncTask<String, Integer, ArrayList<List<HashMap<String, String>>>> {
private TextView mTextView;
protected ParserTask() {
super();
mTextView = null;
}
// Set the TextView to display
public void setTextView(TextView textView) {
mTextView = textView;
}
@Override
protected ArrayList<List<HashMap<String, String>>> doInBackground(String... jsonData) {
try {
ArrayList<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
for (int i = 0; i < jsonData.length; i++) {
JSONObject jObject = new JSONObject(jsonData[i]);
DirectionsJSONParser parser = new DirectionsJSONParser();
routes = (ArrayList<List<HashMap<String, String>>>) parser.parse(jObject);
if (isCancelled()) break;
}
return routes;
} catch (Exception e) {
Log.d("Background Task", e.toString());
return null; // Failed, return null
}
}
@Override
protected void onPostExecute(ArrayList<List<HashMap<String, String>>> result) {
if (result.size() < 1) {
Toast.makeText(getActivity(), "No Points", Toast.LENGTH_LONG).show();
return;
}
for (int i = 0; i < result.size(); i++) {
List<HashMap<String, String>> path = result.get(i);
String distance = "No distance";
for (int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
if (j == 0) {
distance = point.get("distance");
continue;
}
}
mTextView.setText("(" + distance + " away)");
}
}
}
/* private class FirstDownloadTask extends AsyncTask<String, Void, ArrayList<String>> {
@Override
protected ArrayList<String> doInBackground(String... urlList) {
try {
ArrayList<String> returnList = new ArrayList<String>();
for (String url : urlList) {
// Fetching the data from web service
String data = Locations.this.downloadUrl(url);
returnList.add(data);
}
return returnList;
} catch (Exception e) {
return null; // Failed, return null
}
}
@Override
protected void onPostExecute(ArrayList<String> results) {
super.onPostExecute(results);
TextView tv1 = (TextView) getActivity().findViewById(R.id.textView1);
FirstParserTask parserTask = new FirstParserTask();
for (String url : results) {
parserTask.execute(url);
parserTask.setFirstTextView(tv1);
}
}
}
private class FirstParserTask extends AsyncTask<String, Integer, ArrayList<List<HashMap<String, String>>>> {
private TextView mTextView;
protected FirstParserTask() {
super();
mTextView = null;
}
public void setFirstTextView(TextView textView) { mTextView = textView; }
@Override
protected ArrayList<List<HashMap<String, String>>> doInBackground(String... jsonData) {
try {
ArrayList<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
for (int i = 0; i < jsonData.length; i++) {
JSONObject jObject = new JSONObject(jsonData[i]);
DirectionsJSONParser parser = new DirectionsJSONParser();
// Starts parsing data
routes = (ArrayList<List<HashMap<String, String>>>) parser.parse(jObject);
}
return routes;
} catch (Exception e) {
return null; // Failed, return null
}
}
@Override
protected void onPostExecute(
ArrayList<List<HashMap<String, String>>> result) {
if (result.size() < 1) {
return;
}
// Traversing through all the routes
for (int i = 0; i < result.size(); i++) {
List<HashMap<String, String>> path = result.get(i);
String distance = "No distance";
for (int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
if (j == 0) {
distance = point.get("distance");
continue;
}
}
mTextView.setText("Location 1 is (" + distance + " away)");
}
}
}
private class SecondDownloadTask extends AsyncTask<String, Void, ArrayList<String>> {
@Override
protected ArrayList<String> doInBackground(String... urlList) {
try {
ArrayList<String> returnList = new ArrayList<String>();
for (String url : urlList) {
// Fetching the data from web service
String data = Locations.this.downloadUrl(url);
returnList.add(data);
}
return returnList;
} catch (Exception e) {
return null; // Failed, return null
}
}
@Override
protected void onPostExecute(ArrayList<String> results) {
super.onPostExecute(results);
TextView tv2 = (TextView) getActivity().findViewById(R.id.textView2);
SecondParserTask parserTask = new SecondParserTask();
for (String url : results) {
parserTask.execute(url);
parserTask.setSecondTextView(tv2);
}
}
}
private class SecondParserTask extends AsyncTask<String, Integer, ArrayList<List<HashMap<String, String>>>> {
private TextView mTextView;
protected SecondParserTask() {
super();
mTextView = null;
}
public void setSecondTextView(TextView textView) { mTextView = textView; }
// Parsing the data in non-ui thread
@Override
protected ArrayList<List<HashMap<String, String>>> doInBackground(String... jsonData) {
try {
ArrayList<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
for (int i = 0; i < jsonData.length; i++) {
JSONObject jObject = new JSONObject(jsonData[i]);
DirectionsJSONParser parser = new DirectionsJSONParser();
routes = (ArrayList<List<HashMap<String, String>>>) parser.parse(jObject);
}
return routes;
} catch (Exception e) {
return null; // Failed, return null
}
}
@Override
protected void onPostExecute(
ArrayList<List<HashMap<String, String>>> result) {
if (result.size() < 1) { return; }
// Traversing through all the routes
for (int i = 0; i < result.size(); i++) {
List<HashMap<String, String>> path = result.get(i);
String distance = "No distance";
for (int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
if (j == 0) {
distance = point.get("distance");
continue;
}
}
mTextView.setText("Location 2 (" + distance + " away)");
}
}
} */
}
DirectionsJSONParser.java
public class DirectionsJSONParser {
public List<List<HashMap<String, String>>> parse(JSONObject jObject) {
List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
JSONArray jRoutes = null;
JSONArray jLegs = null;
JSONArray jSteps = null;
JSONObject jDistance = null;
JSONObject jDuration = null;
try {
jRoutes = jObject.getJSONArray("routes");
/** Traversing all routes */
for (int i = 0; i < jRoutes.length(); i++) {
jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
List<HashMap<String, String>> path = new ArrayList<HashMap<String, String>>();
/** Traversing all legs */
for (int j = 0; j < jLegs.length(); j++) {
/** Getting distance from the json data */
jDistance = ((JSONObject) jLegs.get(j))
.getJSONObject("distance");
HashMap<String, String> hmDistance = new HashMap<String, String>();
hmDistance.put("distance", jDistance.getString("text"));
/** Getting duration from the json data */
jDuration = ((JSONObject) jLegs.get(j))
.getJSONObject("duration");
HashMap<String, String> hmDuration = new HashMap<String, String>();
hmDuration.put("duration", jDuration.getString("text"));
/** Adding distance object to the path */
path.add(hmDistance);
/** Adding duration object to the path */
path.add(hmDuration);
jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");
/** Traversing all steps */
for (int k = 0; k < jSteps.length(); k++) {
String polyline = "";
polyline = (String) ((JSONObject) ((JSONObject) jSteps
.get(k)).get("polyline")).get("points");
List<LatLng> list = this.decodePoly(polyline);
/** Traversing all points */
for (int l = 0; l < list.size(); l++) {
HashMap<String, String> hm = new HashMap<String, String>();
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 e) {
e.printStackTrace();
} catch (Exception e) {
}
return routes;
}
private List<LatLng> decodePoly(String encoded) {
List<LatLng> poly = new ArrayList<LatLng>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
LatLng p = new LatLng(((lat / 1E5)), ((lng / 1E5)));
poly.add(p);
}
return poly;
}
}