Search code examples
androidgoogle-mapsdirections

Google Maps crashes when you cannot drive to a location


I have a google maps project where you can type in an address and you will get a marker displaying, the address, the duration (travelling by car), and the distance from the users location to point B. It works great!

My problem though, is that whenever I put a location that is not accessed by a car, the app crashes. I'm not looking for anything major, and I do not need anything else than the driving distance, so for the user to just be told that you can't drive here, is just fine for me.

I'm using JSONParsing to parse the address after an UrlRequest. legs, distance, duration, end_address, end-lat, end-lng, are the values that I'm fetching from this file:

legs: [
{
    distance: {
        text: "547 km",
                value: 547015
    },
    duration: {
        text: "5 h 23 min",
                value: 19361
    },
    end_address: "Montreal, Quebec, Kanada",
            end_location: {
    lat: 45.5017123,
            lng: -73.5672184
},
    start_address: "Toronto, Ontario, Kanada",
            start_location: {
    lat: 43.6533096,
            lng: -79.3827656
},
    steps: [
    {
        distance: {
            text: "0,3 km",
                    value: 280
        },
        duration: {
            text: "1 min",
                    value: 66
        },
        end_location: {
            lat: 43.6557259,
                    lng: -79.3837337
        },
        html_instructions: "",
                polyline: {
        points: "e`miGhmocNs@Rm@N]JmA^KBcAZSFWHe@Nk@Pa@Le@L"
    },
        start_location: {
            lat: 43.6533096,
                    lng: -79.3827656
        },
        travel_mode: "DRIVING"
    },

So my question is, does anyone have any suggestions as to what kind of conditions I should have for this kind of method to run.

if(!=travel_mode: "DRIVING")
{
 Toast.makeText(MapsActivity.this, "You cannot drive there", 
    Toast.LENGTH:SHORT).show();
}
else
{
   execute code;
}

Fetch the travel_mode and have it as a condition somehow? Thank you in advance!

My whole code,

The main class, when you press a button the address will be converted

private void init() {
    searchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            dataTransfer = new Object[2];
            url = getDirectionsUrl();
            GetDistances getDistances = new GetDistances();
            dataTransfer[0] = mMap;
            dataTransfer[1] = url;
            getDistances.execute(dataTransfer);
            return false;
        }
    });

Building the URL...

private String getDirectionsUrl()
{
    //WORKS
    //https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&key=API_KEY"
    StringBuilder googleDirectionsUrl = new StringBuilder("https://maps.googleapis.com/maps/api/directions/json?");
    //Possible two textfields with origin being another textfield
    googleDirectionsUrl.append("origin="+myLat+","+myLng);
    googleDirectionsUrl.append("&destination="+searchText.getText().toString());
    googleDirectionsUrl.append("&key="+"API_KEY");

    return googleDirectionsUrl.toString();
}

Sending the Url to be parsed...

public class DataParser {

private HashMap<String, String> getDuration(JSONArray googleDirectionsJson) {
    HashMap<String, String> googleDirectionsMap = new HashMap<>();
    String duration = "";
    String distance = "";
    String title = "";

    Log.d("json response", googleDirectionsJson.toString());
    try {
        duration = googleDirectionsJson.getJSONObject(0).getJSONObject("duration").getString("text");
        distance = googleDirectionsJson.getJSONObject(0).getJSONObject("distance").getString("text");
        title = googleDirectionsJson.getJSONObject(0).getString("end_address");

        googleDirectionsMap.put("duration", duration);
        googleDirectionsMap.put("distance", distance);
        googleDirectionsMap.put("end_address", title);

    } catch (JSONException e) {
        e.printStackTrace();
    }
    return googleDirectionsMap;
}

public HashMap<String, String> parseDirections(String jsonData) {
    JSONArray jsonArray = null;
    JSONObject jsonObject;

    try {
        jsonObject = new JSONObject(jsonData);
        jsonArray = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs");
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return getDuration(jsonArray);
}

private HashMap<String, Double> getLatLng(JSONArray googleLatLngJson) {
    HashMap<String, Double> googleLatLngMap = new HashMap<>();
    Double latitude = 0.0;
    Double longitude = 0.0;

    try {
        latitude = googleLatLngJson.getJSONObject(0).getJSONObject("end_location").getDouble("lat");
        longitude = googleLatLngJson.getJSONObject(0).getJSONObject("end_location").getDouble("lng");

        googleLatLngMap.put("lat", latitude);
        googleLatLngMap.put("lng", longitude);
        Log.d("json response", googleLatLngMap.toString());

    } catch (JSONException e) {
        e.printStackTrace();
    }
    return googleLatLngMap;
}

public HashMap<String, Double> parseLatLng(String jsonData) {
    JSONArray jsonArray = null;
    JSONObject jsonObject;

    try {
        jsonObject = new JSONObject(jsonData);
        jsonArray = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs");
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return getLatLng(jsonArray);
}

}

Getting the values from the JSONparsed hashmaps and putting them into new hashmaps to add the markers with their values

public class GetDistances extends AsyncTask<Object, String, String>{

GoogleMap mMap;
String url;
String googleDirectionsData;
String duration, distance;
Double latitude, longitude;
LatLng latLng;
String title;

@Override
protected String doInBackground(Object... objects) {
   mMap = (GoogleMap)objects[0];
   url = (String)objects[1];

   HttpHandler httpHandler = new HttpHandler();
   try
   {
       googleDirectionsData = httpHandler.readUrl(url);
   }
   catch(IOException e)
   {
       e.printStackTrace();
   }
   return googleDirectionsData;
}

@Override
protected void onPostExecute(String s)
{
    DataParser parser = new DataParser();

    HashMap<String, String> directionsList = null;
    directionsList = parser.parseDirections(s);
    duration = directionsList.get("duration");
    distance = directionsList.get("distance");
    title = directionsList.get("end_address");


    HashMap<String, Double> positionList = null;
    positionList = parser.parseLatLng(s);
    latitude = positionList.get("lat");
    longitude = positionList.get("lng");
    latLng = (new LatLng(latitude, longitude));

    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13));
    MarkerOptions markerOptions = new MarkerOptions()
            .position(latLng)
            .draggable(true)
            .title(title);
    markerOptions.snippet("Distance: " + distance + ", " + "Duration: " + duration);

    mMap.addMarker(markerOptions);
}
}

"API_KEY" - is my actual key, just trying to keep it private.

SOLVED I just made a try catch in the onPostExecute method, and it solved the crash.

public class GetDestination extends AsyncTask<Object, String, String>{

GoogleMap mMap;
String url;
String googleDirectionsData;
String duration, distance;
Double latitude, longitude;
LatLng latLng;
String title;

private static Context context;
public GetDestination(Context c){
    context = c;
}

public static void showToast(){
    Toast.makeText(context, "You can't drive through the oceans!", Toast.LENGTH_LONG).show();
}

@Override
protected String doInBackground(Object... objects) {
   mMap = (GoogleMap)objects[0];
   url = (String)objects[1];

   HttpHandler httpHandler = new HttpHandler();
   try
   {
       googleDirectionsData = httpHandler.readUrl(url);
   }
   catch(IOException e)
   {
       e.printStackTrace();
   }
   return googleDirectionsData;
}

@Override
protected void onPostExecute(String s)
{
    try {
        DataParser parser = new DataParser();

        HashMap<String, String> directionsList = null;
        directionsList = parser.parseDirections(s);
        duration = directionsList.get("duration");
        distance = directionsList.get("distance");
        title = directionsList.get("start_address");


        HashMap<String, Double> positionList = null;
        positionList = parser.parseLatLng(s);
        latitude = positionList.get("lat");
        longitude = positionList.get("lng");

        latLng = (new LatLng(latitude, longitude));

        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13));
        MarkerOptions markerOptions = new MarkerOptions()
                .position(latLng)
                .draggable(true)
                .title(title);
        markerOptions.snippet("Distance: " + distance + ", " + "Duration: " + duration);

        mMap.addMarker(markerOptions);
    }
    catch (Exception e)
    {
        showToast();
        e.printStackTrace();
    }
}
}

Be sure to pass in the context in the Mainactivity class,

searchText1.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                dataTransfer = new Object[2];
                url = getDirectionsUrl();
                GetDestination getDestination = new GetDestination(MapsActivity.this);
                dataTransfer[0] = mMap;
                dataTransfer[1] = url;
                getDestination.execute(dataTransfer);
                return false;
        }
    });

Solution

  • It's great that you have solved the problem yourself. Congrats.

    But the better approach will be to put a log in the response and check the difference between the two responses i.e drivable and not drivable.

    In this way, you could read the exact response and based on the response you can show different messages to the user.

    And of course, a try, catch could be there to handle any kind of exception.

    Hope this Helps.