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

Do Butterknife bindings fail? My code compiles, runs then fails on first line in updateDisplay().

I have tested the code, and attempted to isolate the error. Logcat details indicate that the error is occurring on the first executable line of the updateDisplay() method. If I put in a log.d call to write the temperature value to the log - it does. If I comment out the mTemperatureLabel.setText() line, then the failure moves to the next line. Logging values from getCurrentDetails() and directly from mCurrentWeather indicate that the JSON data is being received correctly. I just can't get it to display correctly. I suspect that the culprit is the Butterknife bindings (yes I am using @Bind).

Ben Deitch
Ben Deitch
Treehouse Teacher

Hey Michael! Could you post the problematic code? And maybe the error message you get as well?

3 Answers

Ben Deitch
STAFF
Ben Deitch
Treehouse Teacher

Hey Michael! Check out the previous video at about the 1:25 mark :)

Thanks Ben. Somehow that part had been overlooked.

Hey Ben,

code as follows

public class MainActivity extends ActionBarActivity {

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

    private CurrentWeather mCurrentWeather;

    @Bind(R.id.timeLabel) TextView mTimeLabel;
    @Bind(R.id.temperatureLabel) TextView mTemperatureLabel;
    @Bind(R.id.humidityValue) TextView mHumidityValue;
    @Bind(R.id.precipValue) TextView mPrecipValue;
    @Bind(R.id.summaryLabel) TextView mSummaryLabel;
    @Bind(R.id.iconImageView) ImageView mIconImageView;

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

        String apiKey = "107b299143955ec47685c28b02686128";
        double latitude = -34.673686;
        double longitude = 148.633763;
        String forecastURL = "https://api.forecast.io/forecast/" + apiKey + "/" + latitude + ","
                + longitude;

        if (isNetworkAvailable()) {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(forecastURL)
                    .build();

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

                }

                @Override
                public void onResponse(Response response) throws IOException {
                    try {
                        String jsonData = response.body().string();
                        Log.v(TAG, jsonData);
                        if (response.isSuccessful()) {
                            mCurrentWeather = getCurrentDetails(jsonData);
                            Log.d(TAG, String.valueOf(mCurrentWeather.getTemperature()));
                            updateDisplay();
                        } else {
                            //Log.v(TAG, response.body().string());
                            alertUserAboutError();
                        }
                    } catch (IOException e) {
                        Log.e(TAG, "Exception caught: ", e);
                    } catch (JSONException e) {
                        Log.e(TAG, "Exception caught: ", e);
                    }
                }
            });
        } else {
            Toast.makeText(this, getString(R.string.network_unavailable), Toast.LENGTH_LONG).show();
        }

        Log.d(TAG, "Main UI code is running!");
    }

    private void updateDisplay() {
        Log.d(TAG, String.valueOf(mCurrentWeather.getTemperature()));
        mTemperatureLabel.setText(String.valueOf(mCurrentWeather.getTemperature()) + "");
        mTimeLabel.setText("At " + mCurrentWeather.getFormattedTime() + " it will be: ");
        mHumidityValue.setText(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.setTime(currently.getLong("time"));
        currentWeather.setHumidity(currently.getDouble("humidity"));
        currentWeather.setIcon(currently.getString("icon"));
        currentWeather.setSummary(currently.getString("summary"));
        currentWeather.setPrecipChance(currently.getInt("precipProbability"));
        currentWeather.setTemperature(currently.getDouble("temperature"));
        currentWeather.setTimeZone(timezone);

        Log.d(TAG, currentWeather.getFormattedTime());
        Log.d(TAG, String.valueOf(currentWeather.getTemperature()));

        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 alertUserAboutError() {
        AlertDialogFragment dialog = new AlertDialogFragment();
        dialog.show(getFragmentManager(), "error_dialog");
    }


}

Runtime logcat messages:

''' 11-11 08:41:54.960 857-857/com.mikelane9143.stormy D/MainActivity: Main UI code is running! 11-11 08:42:01.370 857-939/com.mikelane9143.stormy I/MainActivity: From JSON: Australia/Sydney 11-11 08:42:01.400 857-939/com.mikelane9143.stormy D/MainActivity: 12:42 AM 11-11 08:42:01.400 857-939/com.mikelane9143.stormy D/MainActivity: 59.71 11-11 08:42:01.400 857-939/com.mikelane9143.stormy D/MainActivity: 59.71 11-11 08:42:01.410 857-939/com.mikelane9143.stormy D/MainActivity: 59.71 11-11 08:42:01.450 857-939/com.mikelane9143.stormy E/AndroidRuntime: at com.mikelane9143.stormy.MainActivity.updateDisplay(MainActivity.java:96) 11-11 08:42:01.450 857-939/com.mikelane9143.stormy E/AndroidRuntime: at com.mikelane9143.stormy.MainActivity.access$200(MainActivity.java:29) 11-11 08:42:01.450 857-939/com.mikelane9143.stormy E/AndroidRuntime: at com.mikelane9143.stormy.MainActivity$1.onResponse(MainActivity.java:75) '''

Ben Deitch
Ben Deitch
Treehouse Teacher

Hmm not sure. We should be able to see a more descriptive error message though. If you change the Log Level to 'Error' and change the box at the top right of Logcat to 'No Filters', are you able to see more about the error?

Logcat with No filters and Error level gives:

''' 11-12 07:33:29.690 902-933/com.mikelane9143.stormy E/AndroidRuntime: at com.mikelane9143.stormy.MainActivity.updateDisplay(MainActivity.java:96) 11-12 07:33:29.690 902-933/com.mikelane9143.stormy E/AndroidRuntime: at com.mikelane9143.stormy.MainActivity.access$200(MainActivity.java:29) 11-12 07:33:29.690 902-933/com.mikelane9143.stormy E/AndroidRuntime: at com.mikelane9143.stormy.MainActivity$1.onResponse(MainActivity.java:75) 11-12 07:33:37.800 359-388/system_process E/InputDispatcher: channel 'b3100858 com.mikelane9143.stormy/com.mikelane9143.stormy.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed! '''

Also worth noting - the code did work until adding in the Icon feature