Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android Build a Weather App (2015) Hooking Up the Model to the View Setting the Weather Icon

My App is crashing after I made changes. There is a NullPointerException in the updateDisplay() method.

When I run the project, the screen displays for a couple of seconds, with the default hard coded values and then app crashes. My updateDisplay method is as follows:

private void updateDisplay() {

        mTemperatureLabel.setText(mCurrentWeather.getTemperature()+"");
        mTimeLabel.setText("At "+mCurrentWeather.getFormattedTime()+" it will be ");
        mHumidityValue.setText((int) mCurrentWeather.getHumidity()+"");
        mPrecipValue.setText(mCurrentWeather.getPrecipChance()+"%");
        mSummaryLabel.setText(mCurrentWeather.getSummary());

        Drawable drawable = getResources().getDrawable(mCurrentWeather.getIconId());
        mIconImageView.setImageDrawable(drawable);
    }

and the Logcat shows (Line 106 has mTemperatureLabel.setText(...):

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.vuesol.stormy, PID: 2706
 java.lang.NullPointerException: Attempt to  invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference

at com.example.vuesol.stormy.MainActivity.updateDisplay(MainActivity.java:106)

at com.example.vuesol.stormy.MainActivity.access$200(MainActivity.java:27)

at com.example.vuesol.stormy.MainActivity$1$1.run(MainActivity.java:75) 

at android.os.Handler.handleCallback(Handler.java:790)

at android.os.Handler.dispatchMessage(Handler.java:99)

 at android.os.Looper.loop(Looper.java:164)  

at android.app.ActivityThread.main(ActivityThread.java:6494)  

at java.lang.reflect.Method.invoke(Native Method) 

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

Please guide me on how to go about it.

2 Answers

Can you post all the Activity - mTemperatureLabel is holding null. I need to see where mTemperatureLabel is declared and initialized.

Steve.

<snip>

public class MainActivity extends AppCompatActivity {

    public static final String TAG = MainActivity.class.getSimpleName();

    private CurrentWeather mCurrentWeather;

    @BindView(R.id.labelTime) TextView mTimeLabel;
    @BindView(R.id.labelTemperature) TextView mTemperatureLabel;
    @BindView(R.id.labelHumidity) TextView mHumidityValue;
    @BindView(R.id.labelPrecip) TextView mPrecipValue;
    @BindView(R.id.labelSummary) TextView mSummaryLabel;
    @BindView(R.id.imageViewIcon) ImageView mIconImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);

        String apiKey = "*** EDITED OUT BY MODERATOR ***";
        double latitude = 37.8267;
        double longitude = -122.4233;
        String forescastUrl = "https://api.darksky.net/forecast/"+apiKey+
                "/"+latitude+","+longitude;

        if(isNetworkAvailable()) {

            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(forescastUrl)
                    .build();
            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);
                        if (response.isSuccessful()) {
                            mCurrentWeather = getCurrentDetails(jsonData);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    updateDisplay();
                                }
                            });

                        } else {
                            alertUserAboutTheError();
                        }
                    }
                    catch (IOException e) {
                        Log.e(TAG, "Exception Caught : ", e);
                    }
                    catch (JSONException e) {
                        Log.e(TAG, "Exception Caught : ", e);
                    }
                    catch (NullPointerException e) {
                        Log.e(TAG, "Exception Caught : ", e);
                    }
                }
            });
        }
        else{
            Toast.makeText(MainActivity.this, R.string.network_unavailable_message,
                    Toast.LENGTH_LONG).show();
        }
        Log.d(TAG, "Main UI Code is Running!");


    }

    private void updateDisplay() {

        mTemperatureLabel.setText(mCurrentWeather.getTemperature()+"");
        mTimeLabel.setText("At "+mCurrentWeather.getFormattedTime()+" it will be ");
        mHumidityValue.setText((int) mCurrentWeather.getHumidity()+"");
        mPrecipValue.setText(mCurrentWeather.getPrecipChance()+"%");
        mSummaryLabel.setText(mCurrentWeather.getSummary());

        Drawable drawable = getResources().getDrawable(mCurrentWeather.getIconId());
        mIconImageView.setImageDrawable(drawable);
    }

    private CurrentWeather getCurrentDetails(String jsonData) throws JSONException {

        JSONObject 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.setPrecipChance(currently.getDouble("precipProbability"));
        currentWeather.setSummary(currently.getString("summary"));
        currentWeather.setTemperature(currently.getInt("temperature"));
        currentWeather.setTimeZone(timezone);

        Log.d(TAG,currentWeather.getFormattedTime());

        return currentWeather;
    }

    private boolean isNetworkAvailable() {
        ConnectivityManager manager = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();

        boolean isAvailable = false;


        if(networkInfo != null && networkInfo.isConnected()){
            isAvailable = true;
        }
        return isAvailable;
    }

    private void alertUserAboutTheError() {

        AlertDialogFragment dialog = new AlertDialogFragment();
        dialog.show(getFragmentManager(),"error_dialog");
    }
}

The most likely failure here is that mCurrentWeather is null. Inside onResponse you call getCurrentDetails and assign the result of that into mCurrentWeather. As soon as you use mCurrentWeather, there's a null issue.

Add a breakpoint at mCurrentWeather = getCurrentDetails(jsonData); and step through the code to see if the json works. Does your log of jsonData produce the right output in the log?

Steve.

Thanks a lot for the prompt replies Steve.

The Log is displayed as follows:

02-13 23:14:25.657 5157-5181/? V/MainActivity: {"latitude":37.8267,"longitude":-122.4233,"timezone":"America/Los_Angeles","currently":{"time":1518563665,"summary":"Clear","icon":"clear-day","nearestStormDistance":0,"precipIntensity":0.0013,"precipIntensityError":0.0004,"precipProbability":0.04,"precipType":"rain","temperature":62.03,"apparentTemperature":62.03,"dewPoint":30.54,"humidity":0.3,"pressure":1021.05,"windSpeed":1.28,"windGust":3.86,"windBearing":256,"cloudCover":0.04,"uvIndex":2,"visibility":10,"ozone":272.1},"minutely":{"summary":"Clear for the hour.","icon":"clear-day","data":[{"time":1518563640,"precipIntensity":0,"precipProbability":0},{"time":1518563700,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.09,"precipType":"rain"},{"time":1518563760,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.32,"precipType":"rain"},{"time":1518563820,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.45,"precipType":"rain"},{"time":1518563880,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.34,"precipType":"rain"},{"time":1518563940,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.17,"precipType":"rain"},{"time":1518564000,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.08,"precipType":"rain"},{"time":1518564060,"precipIntensity":0,"precipProbability":0},{"time":1518564120,"precipIntensity":0.003,"precipIntensityError":0,"precipProbability":0.01,"precipType":"rain"},{"time":1518564180,"precipIntensity":0,"precipProbability":0},{"time":1518564240,"precipIntensity":0,"precipProbability":0},{"time":1518564300,"precipIntensity":0,"precipProbability":0},{"time":1518564360,"precipIntensity":0,"precipProbability":0},{"time":1518564420,"precipIntensity":0,"precipProbability":0},{"time":1518564480,"precipIntensity":0,"precipProbability":0},{"time":1518564540,"precipIntensity":0,"precipProbability":0},{"time":1518564600,"precipIntensity":0,"precipProbability":0},{"time":1518564660,"precipIntensity":0,"precipProbability":0},{"time":1518564720,"precipIntensity":0,"precipProbability":0},{"time":1518564780,"precipIntensity":0,"precipProbability":0},{"time":1518564840,"precipIntensity":0,"precipProbability":0},{"time":1518564900,"precipIntensity":0,"precipProbability":0},{"time":1518564960,"precipIntensity":0,"precipProbability":0},{"time":1518565020,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.01,"precipType":"rain"},{"time":1518565080,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.01,"precipType":"rain"},{"time":1518565140,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.02,"precipType":"rain"},{"time":1518565200,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.03,"precipType":"rain"},{"time":1518565260,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.04,"precipType":"rain"},{"time":1518565320,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.05,"precipType":"rain"},{"time":1518565380,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.07,"precipType":"rain"},{"time":1518565440,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.07,"precipType":"rain"},{"time":1518565500,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.07,"precipType":"rain"},{"time":1518565560,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.08,"precipType":"rain"},{"time":1518565620,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.06,"precipType":"rain"},{"time":1518565680,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.06,"precipType":"rain"},{"time":1518565740,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.06,"precipType":"rain"},{"time":1518565800,"precipIntensity":0.003,"precipIntensityError":0.001,"precipProbability":0.05,"precipType":"rain"},{"time":1518565860,"precipIntensity": 02-13 23:14:25.720 5157-5181/? I/MainActivity: From JSON : America/Los_Angeles 02-13 23:14:25.725 5157-5181/? D/MainActivity: 3:14 PM

No problem for the prompt replies - I want to get you up and running, although I'm running out of time here as it's 23:15.

The JSON is clearly working. Great. So, let's see if the issue is to do with that particular label. Comment out the line mTemperatureLabel.setText(mCurrentWeather.getTemperature()); and let's see if that 'solves' the problem or moves it to the next line.

I am sure I dealt with this same issue about 4 years ago but I just can't remember the solution. So, let's go round the houses and find the fix!

Steve.

I see a warning on all the setText calls in updateDisplay() method except for summary. The warning says :

"Do not concatenate text displayed with setText. Use resource string with placeholders. less... (⌘F1) When calling TextView#setText * Never call Number#toString() to format numbers; it will not handle fraction separators and locale-specific digits properly. Consider using String#format with proper format specifications (%d or %f) instead. * Do not pass a string literal (e.g. "Hello") to display text. Hardcoded text can not be properly translated to other languages. Consider using Android resource strings instead. * Do not build messages by concatenating text chunks. Such messages can not be properly translated. More info: http://developer.android.com/guide/topics/resources/localization.html"

I commented out the 4 setText calls and just left the summary call running, but it still gives the same Exception.

You re-posted your code by editing a comment? I'll, again, edit out your API key. Don't change previous posts as that's what I'm looking at to find the issue!

OK - the NullPointerException must have moved? Is that on summary now? The warning you are seeing is about good Android coding; ignore it for now - that's "detail". Do you have an exception; is it the same one, where is it thrown? Do you use Github/BitBucket?

I was making various changes, thus, I initially posted an edited code. The code currently available is the original code that I have on my system.

Yes, the NullPointerException moved to line 111 (summary line). The same exception as earlier.

Yes, I do have GitHub.

Sorry - but I need to go to sleep as I have a pile of driving to do tomorrow.

Push this up to Github and send me the link. Look me up on there; I'm OnlySteveH.

Add watches in the updateDisplay method - find out what's throwing null. The JSON seems fine but that's not reaching the method. Put some toasts in the code to see what variable is holding what at carious points in the code.

I might get a chance to look at this over the next couple of days but I am away with work in hotels, so may not get chance.

Keep me posted on progress.

Steve.

Thanks a lot for the help.

Yes, I will post the GitHub link. And try the fixes that you suggested. I'll also try to look it up online.

I'll definitely update on the progress.

Once again, thanks a lot for helping me, though it was late for you. Really appreciate your prompt responses.

I commented out the call to updateDisplay() method and in the run() method I put toasts to get each value, one after the other. All the values were displayed fine by the toast.

I assume the problem is with binding the variables using butterKnife.

The dependency I added was compile 'com.jakewharton:butterknife:8.8.1'

I added this line:

annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

Now it is working as expected. Thanks a lot for the help again.