3

I tried to get distance between two points

This is the error

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference at com.example.android.algorithm.MainActivity.distancematrix(MainActivity.java:209) at com.example.android.algorithm.MainActivity$1.onClick(MainActivity.java:92) at android.view.View.performClick(View.java:5207) at android.view.View$PerformClick.run(View.java:21177) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5441) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

This is the code portion that Cause the error

public  void distancematrix()
     {
         String k="str";
         double lat1,lat2,lng1,lng2;
         for(int i=0;i<5;i++) {
             lat1=givenlatlng[i][0];
             lng1=givenlatlng[i][1];

             for (int j = 0; j < 5; j++) {
                 lat2=givenlatlng[j][0];
                 lng2=givenlatlng[j][1];
                 k=getDistance(lat1,lng1,lat2,lng2);
                 DistanceMatrix[i][j] = Double.parseDouble(k.substring(0,k.length()-2));
             }

         }

     }

The givenlatlang contains latitude & longitude

the getDistance function

public String getDistance(final double lat1, final double lon1, final double lat2, final double lon2){
        final String[] parsedDistance = new String[1];
        final String[] response = new String[1];
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    URL url = new URL("http://maps.googleapis.com/maps/api/directions/json?origin=" + lat1 + "," + lon1 + "&destination=" + lat2 + "," + lon2 + "&sensor=false&units=metric&mode=driving");
                    final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    InputStream in = new BufferedInputStream(conn.getInputStream());
                    response[0] = org.apache.commons.io.IOUtils.toString(in, "UTF-8");

                    JSONObject jsonObject = new JSONObject(response[0]);
                    JSONArray array = jsonObject.getJSONArray("routes");
                    JSONObject routes = array.getJSONObject(0);
                    JSONArray legs = routes.getJSONArray("legs");
                    JSONObject steps = legs.getJSONObject(0);
                    JSONObject distance = steps.getJSONObject("distance");
                    parsedDistance[0] =distance.getString("text");

                } catch (ProtocolException e) {
                    e.printStackTrace();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {``
            e.printStackTrace();
        }
        return parsedDistance[0];
    }
}`
Harshad Pansuriya
  • 20,189
  • 8
  • 67
  • 95
  • 2
    Can you post the code for `getDistance()`? I believe it's returning `null`, causing the `NullPointerException` for `k` on the next line. – Michael Dodd Mar 23 '17 at 15:31
  • 1
    Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Renats Stozkovs Mar 23 '17 at 16:37
  • Out of interest, why are you using a 1-length `String` array and not just a `String` object? – Michael Dodd Mar 25 '17 at 16:12
  • Also, you need to add better error-handling for invalid coordinates. Setting the origin and destination to [null island](https://en.wikipedia.org/wiki/Null_Island) results in an empty array for `routes`. This is reflected by `status` being `ZERO_RESULTS` – Michael Dodd Mar 25 '17 at 16:17

1 Answers1

2

Basically you're trying to force an asynchronous action to become synchronous i.e. making a web request in the middle of a for loop and trying to latch it onto the UI thread. On top of that, you have poor error handling, so that if any of your catch statements are called then the default value of parsedDistance[1] will be returned (i.e. null). Too much potential to go wrong.

Firstly I'd recommend looking into AsyncTask for performing network operations. You can queue up your requests, have them process one by one and then show the results when done, with the added advantage of not slowing down the UI thread.

You will also need to add a delay in between your requests too. One of the problems I ran into with debugging your code was hitting the query rate limit after 12 requests. See if there's a way of limiting your API calls to as few as possible.

With all this taken into consideration, here's how I'd restructure your code:

private class DistanceMatrixRunner extends AsyncTask<double[][], Void, double[][]> {

    private String getDistance(final double lat1, final double lon1, final double lat2, final double lon2){
        String parsedDistance = null;

        try {
            URL url = new URL("http://maps.googleapis.com/maps/api/directions/json?origin=" + lat1 + "," + lon1 + "&destination=" + lat2 + "," + lon2 + "&sensor=false&units=metric&mode=driving");
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            InputStream in = new BufferedInputStream(conn.getInputStream());
            String response = org.apache.commons.io.IOUtils.toString(in, "UTF-8");

            JSONObject jsonObject = new JSONObject(response);
            JSONArray array = jsonObject.getJSONArray("routes");
            JSONObject routes = array.getJSONObject(0);
            JSONArray legs = routes.getJSONArray("legs");
            JSONObject steps = legs.getJSONObject(0);
            JSONObject distance = steps.getJSONObject("distance");
            parsedDistance =distance.getString("text");

        } catch (IOException | JSONException e) {
            e.printStackTrace();
        }

        return parsedDistance;
    }

    @Override protected double[][] doInBackground(double[][]... params) {
        if (params.length == 0) return new double[0][];

        String k;
        double lat1,lat2,lng1,lng2;

        final double[][] latLngData = params[0];
        final int length = latLngData.length;
        double[][] out = new double[length][length];

        for(int i = 0; i < length; i++) {
            lat1 = latLngData[i][0];
            lng1 = latLngData[i][1];

            for (int j = 0; j < length; j++) {
                lat2 = latLngData[j][0];
                lng2 = latLngData[j][1];
                k = getDistance(lat1,lng1,lat2,lng2);
                out[i][j] = Double.parseDouble(k.substring(0,k.length()-2));

                try {
                    // Avoid the API rate limit
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        return out;
    }

    @Override
    protected void onPostExecute(double[][] doubles) {
        super.onPostExecute(doubles);
        distanceMatrix = doubles;
        // Do any other post-complete updates here
    }
}

Which can be executed using (new DistanceMatrixRunner()).execute(givenlatlng);

Michael Dodd
  • 10,102
  • 12
  • 51
  • 64
  • Thank you for your code ,but i have an error in pasting the above code ... can not resolve symbol distanceMatrix used in OnpostExecute...can you help me i am new to this android programming. so please help me even if it is stupid Question –  Mar 27 '17 at 12:09
  • What sort of error? This should be a private class within your main class – Michael Dodd Mar 27 '17 at 12:10
  • That's the same as `DistanceMatrix[][]` in your original code. It's bad practice to start variables with a capital letter, so I'd advise changing `DistanceMatrix` to begin with a lowercase d in the rest of your code – Michael Dodd Mar 27 '17 at 12:16
  • I'd also recommend taking some time to *try and understand what this code does* rather than just copy-pasting it. – Michael Dodd Mar 27 '17 at 12:17
  • No worries. If this answer has helped, then please upvote and accept. – Michael Dodd Mar 27 '17 at 12:30
  • I also need to use this getdistance in another function but it only contain one source latitude & longitude and one destination ,not An array is there a way? –  Mar 27 '17 at 12:34
  • You could move `getDistance()` outside of the `AsyncTask` and create a new `AsyncTask`, or you can create a `double[][]` with only one element and feed it into this `AsyncTask`. Either way, I'd recommend reading up on AsyncTask, trying a few examples yourself, and if you get stuck and can't find an answer, ask another question here. – Michael Dodd Mar 27 '17 at 12:40