所以我正在研究从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>
答案 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.
}
}