Reputation: 3
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
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