Taylor H
Taylor H

Reputation: 3

WeatherApp, setting an image inside and AsyncTask while parsing XML using setImageResource()

SO i'm working on basic weather application that pulls the XML from the Yahoo weather api, parses it, and displays the information. I have an Async Task that in the doInBackground method pulls the xml and uses a stringBuilder to save the xml, and in the onPostExecute parses the XML in to the format I need. I am trying to set an image in the mCondImg ImageView in the post execute, put can't seem to get it working. Eventually I want to have the condImg to change per the codes in the xml

Public API call: https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22warrensburg%2C%20mo%22)&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys

WeatherFragment.java (the fragment that contains ALL of the actual parsed axml and the asynctask classes.)

import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;



    public class WeatherFragment extends Fragment {

        static TextView mLocation, mCondition, mForecast1, mForecast2, mForecast3, mForecast4, mForecast5;
        Handler handler;
        ImageView mCondImg;



    private OnFragmentInteractionListener mListener;

    public WeatherFragment() {
        handler = new Handler();
    }

    public static WeatherFragment newInstance(String param1, String param2) {
        WeatherFragment fragment = new WeatherFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_weather, container, false);
        mLocation = (TextView)  rootView.findViewById(R.id.location);
        mCondition = (TextView) rootView.findViewById(R.id.condition);
        mForecast1 = (TextView) rootView.findViewById(R.id.forecast1);
        mForecast2 = (TextView) rootView.findViewById(R.id.forecast2);
        mForecast3 = (TextView) rootView.findViewById(R.id.forecast3);
        mForecast4 = (TextView) rootView.findViewById(R.id.forecast4);
        mForecast5 = (TextView) rootView.findViewById(R.id.forecast5);
        mCondImg = (ImageView) rootView.findViewById(R.id.condImg);
        new RetrieveData().execute();
        return rootView;
    }

    // TODO: Rename method, update argument and hook method into UI event
    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(Uri uri);
    }

    public void changeCity(String city){
        //updateWeatherData(city);
    }
}

class RetrieveData extends AsyncTask<Void, Void, String> {

    public static String str;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected String doInBackground(Void... urls) {
        try {
            URL url = new URL("https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22warrensburg%2C%20mo%22)&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys");
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            try {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line).append("\n");
                }
                bufferedReader.close();
                str = stringBuilder.toString();

                return stringBuilder.toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "Error getting weather data";
    }


    protected void onPostExecute(String response) {
        if (response == null) {
            response = "Error";
        }

        // Parse xml
        try {
            int forecastCounter = 1;
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser parser = factory.newPullParser();
            parser.setInput(new StringReader(str));
            String tagName = null;
            int event = parser.getEventType();

            while (event != XmlPullParser.END_DOCUMENT) {
                tagName = parser.getName();
                if (event == XmlPullParser.START_TAG) {

                    if (tagName.equals("yweather:location")) {
                        WeatherFragment.mLocation.setText(parser.getAttributeValue(null, "city"));
                        WeatherFragment.mLocation.append(", " + parser.getAttributeValue(null, "region"));

                    }
                    else if (tagName.equals("yweather:condition")) {
                        WeatherFragment.mCondition.setText("Current temperature: " + parser.getAttributeValue(null, "temp") + "\nCurrent conditions: " + parser.getAttributeValue(null, "text"));
                        if (tagName.equals("yweather:code")) {
                            mCondImg.setImageResource(R.drawable.ic_snow);
                        }
                    }
                    else if (tagName.equals("yweather:forecast")) {
                        switch (forecastCounter) {
                            case 1:
                                WeatherFragment.mForecast1.setText(parser.getAttributeValue(null, "day") + " - High: " + parser.getAttributeValue(null, "high") + " - Low: " + parser.getAttributeValue(null, "low") + " - " + parser.getAttributeValue(null, "text"));
                                forecastCounter++;
                                if (WeatherFragment.mCondition.getText().equals("28")) {
                                    //WeatherFragment.mCondImg.setImageResource(R.drawable.ic_sunny);//This works
                                }
                                break;
                            case 2:
                                WeatherFragment.mForecast2.setText(parser.getAttributeValue(null, "day") + " - High: " + parser.getAttributeValue(null, "high") + " - Low: " + parser.getAttributeValue(null, "low") + " - " + parser.getAttributeValue(null, "text"));
                                forecastCounter++;
                                break;
                            case 3:
                                WeatherFragment.mForecast3.setText(parser.getAttributeValue(null, "day") + " - High: " + parser.getAttributeValue(null, "high") + " - Low: " + parser.getAttributeValue(null, "low") + " - " + parser.getAttributeValue(null, "text"));
                                forecastCounter++;
                                break;
                            case 4:
                                WeatherFragment.mForecast4.setText(parser.getAttributeValue(null, "day") + " - High: " + parser.getAttributeValue(null, "high") + " - Low: " + parser.getAttributeValue(null, "low") + " - " + parser.getAttributeValue(null, "text"));
                                forecastCounter++;
                                break;
                            case 5:
                                WeatherFragment.mForecast5.setText(parser.getAttributeValue(null, "day") + " - High: " + parser.getAttributeValue(null, "high") + " - Low: " + parser.getAttributeValue(null, "low") + " - " + parser.getAttributeValue(null, "text"));
                                forecastCounter++;
                                break;
                        }

                    }
                }
                event = parser.next();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        //mWeatherData.setText(str);

    }

}

WeatherFragment.xml (Used for styling the fragment)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="-140sp"
        android:textSize="30sp"
        android:id="@+id/location"/>

    <ImageView
        android:layout_width="300px"
        android:layout_height="300px"
        android:src="@drawable/ic_sunny"
        android:id="@+id/condImg"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="15sp"
        android:layout_marginBottom="7sp"
        android:id="@+id/condition"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="10sp"
        android:textSize="20sp"
        android:text="@string/multiForecast" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="15sp"
        android:layout_marginBottom="7sp"
        android:id="@+id/forecast1" />


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="15sp"
        android:layout_marginBottom="7sp"
        android:id="@+id/forecast2" />



    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="15sp"
        android:layout_marginBottom="7sp"
        android:id="@+id/forecast3" />


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="15sp"
        android:layout_marginBottom="7sp"
        android:id="@+id/forecast4" />



    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="15sp"
        android:layout_marginBottom="7sp"
        android:id="@+id/forecast5" />

    <!--<ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/weather_data"
        />

    </ScrollView>-->

</LinearLayout>

Upvotes: 0

Views: 192

Answers (1)

Karakuri
Karakuri

Reputation: 38605

The problem is you are adding namespaces to the tag names in your code. For example, given this tag:

<yweather:condition
    xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0"
    code="29" 
    date="Sun, 24 Apr 2016 09:00 PM CDT"
    temp="68"
    text="Partly Cloudy" />

The tag name is "condition", not "yweather:condition". The namespace is "yweather". Your check for the proper tag should look like this:

if ("condition".equals(tagName))

If you want to also check that the namespace matches, you can do it like this:

if ("condition".equals(tagName) && "yweather".equals(parser.getNamespace())

It's worth mentioning that your code is doing XML parsing on the main (UI) thread because you are doing it inside of onPostExecute(). You should be doing the parsing inside of doInBackground() instead; onPostExecute() should be reserved for only the smallest amount of code that modifies the UI.

You can take advantage of the fact that AsyncTask is parameterized and have doInBackground() return a class you define to hold the results of the parsing, like so:

private static class WeatherResults {
    private int conditionImage;
    private String condition;
    private String location;
    ...
}

class RetrieveData extends AsyncTask<Void, Void, WeatherResults> {
    @Override
    protected String doInBackground(Void... params) {
        WeatherResults weatherResults = new WeatherResults();
        // make web call
        // parse XML and set results, e.g.
        //    weatherResults.conditionImage = R.drawable.ic_snow;

        return weatherResults;
        // you can return null instead if there's an error
    }

    @Override
    protected void onPostExecute(WeatherResults result) {
        if (result == null) {
            // show error state
            return;
        }

        // update the UI
        mCondImg.setImageResource(result.conditionImage);
        // etc.
    }
}

Upvotes: 0

Related Questions