4

I'm still kinda new to Android programming and I've been trying to make a simple weather app, for practice. This code works fine when I enter a valid city name, however I want to use a toast that shows an error to the user when the name is not valid. But this results in a crash, I tried removing the toast, but my app still crashes.

Here's the code:

public class MainActivity extends AppCompatActivity {

EditText cityName;
TextView resultTextView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    cityName = (EditText) findViewById(R.id.cityName);
    resultTextView = (TextView) findViewById(R.id.resultTextView);

}


public void findWeather(View view)
{
    Log.i("Button", "pressed");


    InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    mgr.hideSoftInputFromWindow(cityName.getWindowToken(), 0);



    try {

        String encodedCityName = URLEncoder.encode(cityName.getText().toString(), "UTF-8");
        DownloadTask task = new DownloadTask();
        task.execute("http://api.openweathermap.org/data/2.5/weather?q=" + encodedCityName +"&appid=***");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        Toast.makeText(getApplicationContext(), "Could not find city", Toast.LENGTH_LONG);

    }

}


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

    @Override
    protected String doInBackground(String... strings) {

        String result = "";
        URL url;
        HttpURLConnection urlConnection;

        try {
            url = new URL(strings[0]);
            urlConnection = (HttpURLConnection) url.openConnection();
            InputStream in = urlConnection.getInputStream();
            InputStreamReader reader = new InputStreamReader(in);

            int data = reader.read();
            while(data != -1)
            {
                char current = (char) data;
                result += current;
                data = reader.read();
            }
            return  result;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);

        try{
            String message = "";
            JSONObject jsonObject = new JSONObject(s);
            String weatherInfo = jsonObject.getString("weather");
            Log.i("weather", weatherInfo);

            JSONArray arr = new JSONArray(weatherInfo);

            for(int i = 0; i < arr.length(); i++)
            {
                JSONObject jsonPart = arr.getJSONObject(i);

                String main = "";
                String description = "";

                main = jsonPart.getString("main");
                description = jsonPart.getString("description");

                if (!main.isEmpty() && !description.isEmpty())
                {
                    message += main + ": " + description + "\r\n";

                }
            }

            if(!message.isEmpty())
            {
                resultTextView.setText(message);

            }
            else
            {
                Toast.makeText(getApplicationContext(), "Could not find city", Toast.LENGTH_LONG);
            }

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


    }
}

and the error mesage:

12-22 22:11:51.204 4858-4858/com.example.aiden.whatstheweather E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.aiden.whatstheweather, PID: 4858

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference at org.json.JSONTokener.nextCleanInternal(JSONTokener.java:116) at org.json.JSONTokener.nextValue(JSONTokener.java:94) at org.json.JSONObject.(JSONObject.java:159) at org.json.JSONObject.(JSONObject.java:176) at com.example.aiden.whatstheweather.MainActivity$DownloadTask.onPostExecute(MainActivity.java:102) at com.example.aiden.whatstheweather.MainActivity$DownloadTask.onPostExecute(MainActivity.java:65) at android.os.AsyncTask.finish(AsyncTask.java:695) at android.os.AsyncTask.-wrap1(Unknown Source:0) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

Nissim R
  • 542
  • 11
  • 29
Aiden
  • 59
  • 1
  • 1
  • 3
  • what is the log value you are getting with this line Log.i("weather", weatherInfo); – Abdul Waheed Dec 23 '17 at 06:33
  • Add your api response in the question, so that it'd be easier for people to debug your code. – Jay Dec 23 '17 at 06:39
  • This error can also come from "empty string", e.g in this code ` URL u = new URL(xml_file); URLConnection conn = u.openConnection();` if *xml_file* is empty, the second line with generate error. Make sure to set it. – TheTechGuy Dec 09 '19 at 08:33

2 Answers2

4

If doInBackground catches exception, it will only print the stack trace and then return null. The null is then passed to onPostExecute. The JSONObject pick the null and hence the crash. So it'd be better to return empty value than null.

In DownloadTask.doInBackground, change

return null;

to

return "";
ThomasEdwin
  • 2,035
  • 1
  • 24
  • 36
4

If any exception occur in doInBackground() its going to return null. Handle it as below.

  @Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
   if(s!=null){
    // Do you work here on success
  }else{
     // null response or Exception occur 
    }
}
ADM
  • 20,406
  • 11
  • 52
  • 83