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.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;
}
}
\$\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)");
            }
        }
    }
}
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.