WeatherApp,在使用setImageResource()解析XML时在里面设置图像和AsyncTask

时间:2016-04-25 00:39:44

标签: android xml android-fragments android-asynctask

所以我正在研究从Yahoo weather api中提取XML的基本天气应用程序,解析它并显示信息。我有一个异步任务,在doInBackground方法中拉取xml并使用stringBuilder保存xml,并在onPostExecute中将XML解析为我需要的格式。我试图在后执行的mCondImg ImageView中设置一个图像,看起来似乎无法让它工作。最终我希望根据xml中的代码更改condImg

公共API调用: https://query.yahooapis.com/v1/public/yql?q=select%20 *%20from%20weather.forecast%20where%20woeid%20英寸20%(选择%20woeid%20from%20geo.places(1)%20where%20text%3D%22warrensburg%2C%20mo%22)及格式= XML&安培; ENV =商店%3A%2F%2Fdatatables.org%2Falltableswithkeys

WeatherFragment.java(包含所有实际解析的axml和asynctask类的片段。)

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(用于样式化片段)

    <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>

1 个答案:

答案 0 :(得分:0)

问题是您是在代码中的标记名称中添加名称空间。例如,给定此标记:

<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" />

标记名称为"condition",而不是"yweather:condition"。名称空间为"yweather"。您对正确标签的检查应如下所示:

if ("condition".equals(tagName))

如果您还要检查命名空间是否匹配,可以这样做:

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

值得一提的是,您的代码正在主(UI)线程上进行XML解析,因为您是在onPostExecute()内进行的。您应该在doInBackground()内部进行解析; onPostExecute()应仅保留用于修改UI的最少量代码。

您可以利用AsyncTask参数化并让doInBackground()返回您定义的类来保存解析结果的事实,如下所示:

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.
    }
}