1
\$\begingroup\$

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.access600ドル(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;
}
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 6, 2013 at 14:32
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Finally figured it out! By doing this, in my application code, I was able to reduce the number of AsyncTask class lines from nearly 400 to 100.

Here's the adjusted code for anyone interested. I'm only including the relevant parts for the sake of saving space.

No changes were made to DirectionsJSONParser.java

Locations.java

public void getLastLocation() {
 // Nothing changed above this...
 // 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); // btw these are completely random
 LatLng dest3 = new LatLng(35.1234567, -82.1234567); // Just for fun, add a 3rd
 LatLng dest4 = new LatLng(35.7654321, -82.7654321); // and a 4th
 Locations.this.markerPoints.add(fromLocation);
 Locations.this.markerPoints.add(dest1);
 Locations.this.markerPoints.add(dest2);
 Locations.this.markerPoints.add(dest3);
 Locations.this.markerPoints.add(dest4);
 String url1 = Locations.this.getDirectionsUrl(fromLocation, dest1);
 String url2 = Locations.this.getDirectionsUrl(fromLocation, dest2);
 String url3 = Locations.this.getDirectionsUrl(fromLocation, dest3);
 String url4 = Locations.this.getDirectionsUrl(fromLocation, dest4);
 new DownloadTask().execute(url1, url2, url3, url4);
}
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) {
 // Fetching the data from web service
 String data = Locations.this.downloadUrl(url);
 returnList.add(data);
 }
 return returnList;
 } catch (Exception e) {
 Log.d("Background Task", e.toString());
 return null; // Failed, return null
 }
 }
 // Executes in UI thread, after the execution of doInBackground()
 @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 tv3 = (TextView) getActivity().findViewById(R.id.textView3);
 TextView tv4 = (TextView) getActivity().findViewById(R.id.textView4);
 String s1 = "Location 1 ";
 String s2 = "Location 2 ";
 String s3 = "Location 3 ";
 String s4 = "Location 4 ";
 TextView[] views = { tv1, tv2, tv3, tv4 };
 String[] strings = { s1, s2, s3, s4 };
 int i = 0;
 for (String url : results) {
 ParserTask parserTask = new ParserTask(views[i], strings[i]);
 parserTask.execute(url);
 i++;
 }
 }
}
/** A class to parse the Google Places in JSON format */
private class ParserTask extends AsyncTask<String, Integer, ArrayList<List<HashMap<String, String>>>> {
 private TextView mTextView;
 private String sString;
 public ParserTask(TextView views, String strings) {
 this.mTextView = views;
 this.sString = strings;
 }
 @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) {
 Log.d("Background task", e.toString());
 return null; // Failed, return null
 }
 }
 // Executes in UI thread, after the parsing process
 @Override
 protected void onPostExecute(ArrayList<List<HashMap<String, String>>> result) {
 if (result.size() < 1) {
 Toast.makeText(getActivity(), "No Points", Toast.LENGTH_LONG).show();
 return;
 }
 // Traversing through all the routes
 for (int i = 0; i < result.size(); i++) {
 // Fetching i-th route
 List<HashMap<String, String>> path = result.get(i);
 String distance = "No distance";
 // Fetching all the points in i-th route
 for (int j = 0; j < path.size(); j++) {
 HashMap<String, String> point = path.get(j);
 if (j == 0) {
 distance = point.get("distance");
 continue;
 }
 }
 // Set TextViews
 for (int t = 0; t < 4; t++) {
 mTextView.setText(sString + "(" + distance + " away)");
 }
 }
 }
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
answered Aug 9, 2013 at 16:01
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.