0

I'm building an application on Android Studio that retrieves weather information in real time thanks to OpenWeatherMap and the API they offer.

The problem is, I'm using two phones with different SDKs. One is SDK 23 / Android 6.0 and the other is SDK 28 / Android 9.0.

Currently on the phone with SDK 23 I have no problem. However on the phone with SDK 28 I have a NullPointerException error. My second activity allows me to display information for city X and its weather information. So, finally the error I'm encountering on the phone with SDK 28 is this one :

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference

I've looked into a lot of things to see where that could have come from, if it wasn't my AsyncTask or whatever, but I really don't see it.

Knowing that on the phone with the oldest version of Android it retrieves well the information from my editText that on the most recent version it doesn't retrieve it at all and the nullpointerException must come from there.

Do you know where this might be coming from?

Here is my AsyncTask :

public class ExecuteTask extends AsyncTask<String, Void, String> {


    @Override
    protected String doInBackground(String... strings) {
        HttpURLConnection con = null ;
        InputStream is = null;

        try {
            con = (HttpURLConnection) ( new URL(strings[0])).openConnection();
            con.setRequestMethod("GET");
            con.setDoInput(true);
            con.setDoOutput(true);
            con.connect();

            // Let's read the response
            StringBuffer buffer = new StringBuffer();
            is = con.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line = null;
            while (  (line = br.readLine()) != null )
                buffer.append(line + "\r\n");

            is.close();
            con.disconnect();
            return buffer.toString();
        }
        catch(Throwable t) {
            t.printStackTrace();
        }
        finally {
            try { is.close(); } catch(Throwable t) {}
            try { con.disconnect(); } catch(Throwable t) {}
        }

        return null;
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        try {
            String message = "";
            String degre="";
            String idMeteo="";

            JSONObject jsonObject = new JSONObject(s);


            String infoWeatherToday = jsonObject.getString("weather");


            JSONObject WeatherTemperature = jsonObject.getJSONObject("main");
            Integer deg = WeatherTemperature.getInt("temp");

            deg = deg - 273;


            JSONArray array = new JSONArray(infoWeatherToday);
            int tablongueur=array.length();


            for (int i = 0; i < tablongueur; i++) {
                JSONObject jsonSecondary = array.getJSONObject(i);


                String main = "";
                //Integer id;


                main = jsonSecondary.getString("main");
                //  id = jsonSecondary.getInt("id");

                switch (main) {
                    case "Clouds":
                        main = "Nuageux";
                        PhotoMeteo.setImageResource(R.drawable.cloud);

                        break;
                    case "Clear":
                        main = "Ensoleillé";
                        PhotoMeteo.setImageResource(R.drawable.sun);

                        break;
                    case "Rain":
                        main = "Pluie";
                        PhotoMeteo.setImageResource(R.drawable.rain);

                        break;
                    case "Snow":
                        main = "Neige";
                        PhotoMeteo.setImageResource(R.drawable.snow);

                        break;
                    case "Smoke":
                        main = "Brouillard";
                        PhotoMeteo.setImageResource(R.drawable.smoke);

                        break;
                    case "Drizzle":
                        main = "Brumeux";
                        PhotoMeteo.setImageResource(R.drawable.drizzle);
                        break;
                    default:
                        main = "Météo introuvable !";
                        PhotoMeteo.setImageResource(R.drawable.ic_warning);
                }


                if (main != "" /*&& id != null*/) {
                    message += main + "\r\n";
                    degre += deg +  "°C";
                    //idMeteo += "L'id de la météo est" +  id;
                }

            }


            if (message != "") {
                resultWeather.setText(message);
                resultDegre.setText(degre);
                //resultIdMeteo.setText(idMeteo);
            } else {
                Toast.makeText(AccueilActivity.this, "Une erreur a eu lieu ", Toast.LENGTH_SHORT).show();
            }


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

And here is the intent that I keep from my first activity called RegisterActivity to give it as a parameter for the "name" of the city

Intent intent = new Intent(RegisterActivity.this, AccueilActivity.class);
                intent.putExtra(EXTRA_TEXT,cityField.getText().toString());
                startActivity(intent);

In my 2nd activity called "AccueilActivity"

Intent intent = getIntent();
    if(intent!=null)
    {
        textViewVille.setText(intent.getStringExtra(EXTRA_TEXT));
        ville = intent.getStringExtra(EXTRA_TEXT);
        FindWeather();

    }

And my final function called FindWeather which execute the AsyncTask

public void FindWeather() {
    cityToFind = ville;

    try {
        ExecuteTask tasky = new ExecuteTask();
        tasky.execute("http://api.openweathermap.org/data/2.5/weather?q=" + cityToFind + "&APPID={MYAPKKEY}&LANG=fr&UNITS=metric");
    } catch (Exception e) {
        e.printStackTrace();
    }

}

Just I don't give you the value of my APK Key because it isn't something interesting but the value is present in the initial code.

If I have a last things to add, ville is a simple TextView and cityToFind the value of my editText on the first activity.

If you need anything of my source code I can give you more.

Thank you.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Nikn
  • 1
  • 1
  • 1

1 Answers1

0

doInBackground is going to return null if there is any exception in your HTTP code.

That is passed to onPostExecute as the parameter.

You then try to constuct a JSONObject(null), which is an invalid argument


All in all, please pick a higher level HTTP library with fault tolerance built in

Comparison of Android networking libraries: OkHTTP, Retrofit, and Volley


I also suggest writing unit tests outside of that class and running them from the IDE rather than a device, so you verify the network calls actually work.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • I only follow a tutorial that I find on Youtube it's the first time I'm trying to do an AsyncTask I understand that it isn't normal. Do you have any advice to fix it because I have no idea how to proceed – Nikn Mar 25 '20 at 18:44
  • Well, do you understand [what a NullPointerException is, and how to read a stacktrace?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) Learning that is honestly how you should proceed. Don't focus on just your code, but actually learn what the error means and where it happens. – OneCricketeer Mar 25 '20 at 18:50
  • The problem of reading the stacktrace is I understand a NullPointerException happen, but why it is different between two SDK ? And why the NullPointerException only happen in the most recently SDK. I'm going to give a try to your link and see what can I do with this. – Nikn Mar 25 '20 at 19:04
  • The API probably isn't important, but Android permissions have changed. You would need to explicitly enable Networking features in the code. That was implemented around SDK 26 https://developer.android.com/training/permissions/requesting Fact of the matter is that you've let the app crash because the reason in my answer. And you are skipping over reading the *real exception* that you have printed in the catch block... – OneCricketeer Mar 25 '20 at 22:33
  • Hi cricket_007, I add the permission for internet, I also tried with Volley this morning and finally it doesn't work. I don't have any solution to fix it. I tried to make a log.e of my result (because I think he is null at the end of the doInBackground() ) but nothing fix it, and i don't understand how I can fix this. – Nikn Mar 26 '20 at 10:52
  • Not sure I follow. Volley doesn't use doInBackground. "Doesn't work" doesn't describe what **does** happen. You can try the other libraries that are linked in the post in my answer – OneCricketeer Mar 27 '20 at 19:47