Android Build a Weather App Hooking Up the Model to the View Plugging in the Data

Fatal Exception Okhttp dispathcer and Null Pointer Exception

I am getting Null pointer exception.... Here is my code.......

public void onResponse(Call call, Response response) throws IOException { try { String jsonData = response.body().string(); Log.v(TAG, jsonData);//printing entire response to the log console.. //write an if block to know whether the resonse is successful or not if (response.isSuccessful()) {

                   currentWeather = getCurrentDetail(jsonData);

                   final CurrentWeather displayWeather = new CurrentWeather(
                           currentWeather.getLocationLabel(),
                           currentWeather.getIcon(),
                           currentWeather.getTime(),
                           currentWeather.getTemperature(),
                           currentWeather.getHumidity(),
                           currentWeather.getPrecipChance(),
                           currentWeather.getSummary(),
                           currentWeather.getTimeZone()
                   );
                   binding.setWeather(displayWeather);
                   runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           //after getting our data we have to set our icon
                           Drawable drawable = getResources().getDrawable(displayWeather.getIconId());
                           iconImageView.setImageDrawable(drawable);
                   }

************* Here is the error code from logcat *****************

E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher Process: com.yogigorle.stormy, PID: 32314 java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.yogigorle.stormy.CurrentWeather.getLocationLabel()' on a null object reference at com.yogigorle.stormy.MainActivity$1.onResponse(MainActivity.java:82) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:216) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:760)

Lauren Moineau
Lauren Moineau
9,344 Points

Hi. Could you paste your entire code from MainActivity.java please? It seems that your currentWeather object is null. Did you get all the data correctly in the logs in the previous lessons?

(If you surround your code with 3 backticks ```, before and after, it will come out formatted)

here is my code from MainActivity.java...

public class MainActivity extends AppCompatActivity {

public CurrentWeather currentWeather;
private ImageView iconImageView;
public static final String TAG = MainActivity.class.getSimpleName(); //TAG creation  ....

final double latitude = 18.783640;
final double longitude = 83.445490;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    getForecast(latitude,longitude);
    Log.d(TAG, "Main code is running smooth");
    }

private void getForecast(double latitude, double longitude) {
    final ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

    iconImageView = findViewById(R.id.iconImageView);

    String apiKey = "8e1dfba784a2942e72029b748cc9cea3";



    String forecastURL = "https://api.darksky.net/forecast/"
            + apiKey + "/" + latitude + "," + longitude;// we will have to refactor it bcoz u want to avoid harcoded text..
    if (isNetworkAvailable()) {

        OkHttpClient client = new OkHttpClient();

        //build a request to dark sky api
        Request request = new Request.Builder().url(forecastURL).build();

        //call a request
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
           try {
               String jsonData = response.body().string();
               Log.v(TAG, jsonData);//printing entire response to the log console..
               //write an if block to know whether the resonse is successful or not
               if (response.isSuccessful()) {

                   currentWeather = getCurrentDetail(jsonData);

                   final CurrentWeather displayWeather = new CurrentWeather(
                           currentWeather.getLocationLabel(),
                           currentWeather.getIcon(),
                           currentWeather.getTime(),
                           currentWeather.getTemperature(),
                           currentWeather.getHumidity(),
                           currentWeather.getPrecipChance(),
                           currentWeather.getSummary(),
                           currentWeather.getTimeZone()
                   );
                   binding.setWeather(displayWeather);
                   runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           //after getting our data we have to set our icon
                           Drawable drawable = getResources().getDrawable(displayWeather.getIconId());
                           iconImageView.setImageDrawable(drawable);
                   }
                   });


               } else {
                   alertUserAboutError();
               }
           }catch (IOException e) {
               Log.e(TAG,"IO exception caught",e);
           }

            }
        });

    }
}

private CurrentWeather getCurrentDetail(String jsonData)  {
    JSONObject forecast;
    try {
        forecast = new JSONObject(jsonData);
        String timeZone = forecast.getString("timezone");

        Log.i(TAG, "From json " + timeZone);
        JSONObject currently = forecast.getJSONObject("currently");
        CurrentWeather currentWeather = new CurrentWeather();
        currentWeather.setHumidity(currently.getDouble("humidity"));
        currentWeather.setTime(currently.getLong("time"));
        currentWeather.setIcon(currently.getString("icon"));
        currentWeather.setLocationLabel("Parvathipuram");
        currentWeather.setPrecipChance(currently.getDouble("precipProbability"));
        currentWeather.setSummary(currently.getString("summary"));
        currentWeather.setTemperature(currently.getDouble("temperature"));
        currentWeather.setTimeZone(timeZone);

        Log.v(TAG,currentWeather.getFormattedTime());
    } catch (JSONException e) {
        Log.v(TAG,"JsonException caught",e);
    }

    return currentWeather;
}

private boolean isNetworkAvailable () {

        //first connect to the system service
        ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        //getting network info
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();

        boolean isAvailable = false;
        if (networkInfo != null && networkInfo.isConnected()) {
            isAvailable = true;
        }
        else{
            Toast.makeText(getApplicationContext(),"Sorry network not available",Toast.LENGTH_SHORT).show();
        }
        return isAvailable;
    }

private void alertUserAboutError() {
    AlertDialogFragment dialog = new AlertDialogFragment();
    dialog.show(getFragmentManager(),"error dialog");
}

public void refreshOnclick(View view){
    Toast.makeText(getApplicationContext(),"Refreshing Data",Toast.LENGTH_LONG).show();
    getForecast(longitude,latitude);

}

}

1 Answer

Lauren Moineau
Lauren Moineau
9,344 Points

Hi Vamshi. The issue is in your getCurrentDetail() method. You are declaring and initialising the currentWeather variable inside your try block (meaning it only exists inside that try block). The method then returns a null currentWeather because the currrentWeather variable inside the try block is not visible, so it returns the currentWeather class variable (declared at the top), which is null by default.

So you need to declare that currentWeather local variable outside the try block, at the top of the method:

CurrentWeather currentWeather = null;  // we need to initialise it as it is a local variable (null is just the default value for an object)

Then, inside your try block, you just write:

currentWeather = new CurrentWeather();

Now your method is no longer returning a null currentWeather, so in onResponse(), currentWeather is not null (because getCurrentDetail() does not return a null Current object) and you no longer get a NullPointerException (NPE) when calling the different getters on that object.

I hope that makes sense :)

P.S. As a word of advice, you should not share your API key publicly. So I would recommend you hit those 3 dots below your post (next to Add Comment) to edit it and remove that key.