Reputation: 366
I've searched all the posts I can find, and none seem to help with my situation. I have an android project that uses web services to pull down hourly weather data and populate a listView with the results.
The weird problem I'm having is that when I debug the project on my android phone, the main activity is blank and the listView isn't populated. If I run the project from android studio with my phone locked, and then unlock my phone the app opens on my phone with all of the listView properly formatted and populated.
I feel like it's a race condition issue between the asynctask and the adapter, but I can't seem to resolve it. I tried making my asyncTask an inner private class and calling notifyDataSetChanged
on the adapter inside the onPostExecute
method, but to no avail. I feel it must be something simple, but I'm relatively new to Android dev, so I'm stuck.
I have three classes that I'll post the pertinent code from
MainActivity.java (onCreate
)
public class MainActivity extends ActionBarActivity {
ArrayList<Weather> w = new ArrayList<Weather>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadWeatherTask myTask = new DownloadWeatherTask(w);
WeatherAdapter myAdapter = new WeatherAdapter(this,w);
ListView l = (ListView) findViewById(R.id.weatherList);
l.setAdapter(myAdapter);
myTask.execute();
}
}
WeatherAdapter.java
public class WeatherAdapter extends ArrayAdapter<Weather>{
public WeatherAdapter(Context context, ArrayList<Weather> weather) {
super(context, R.layout.item_weather, weather);
}
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Weather forecast = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_weather, parent, false);
}
// Lookup view for data population
TextView tvTime = (TextView) convertView.findViewById(R.id.listTime);
TextView tvDescr = (TextView) convertView.findViewById(R.id.listDescr);
TextView tvTemp = (TextView) convertView.findViewById(R.id.listTemp);
TextView tvHumid = (TextView) convertView.findViewById(R.id.listHumid);
ImageView ivWeather = (ImageView) convertView.findViewById(R.id.weatherImg);
// Populate the data into the template view using the data object
tvTime.setText(forecast.time);
tvDescr.setText(forecast.description);
tvTemp.setText(forecast.temperature+"°(F)");
tvHumid.setText(forecast.humidity+"% humidity");
ivWeather.setImageBitmap(forecast.weatherImg);
// Return the completed view to render on screen
return convertView;
}
}
DownloadWeatherTask.java
public class DownloadWeatherTask extends AsyncTask<Void,Void,Void>{
ArrayList<Weather> data;
public DownloadWeatherTask(ArrayList<Weather> a){
data = a;
}
public ArrayList<Weather> getData() {
return data;
}
protected Void doInBackground(Void...params) {
try {
String website = "http://api.wunderground.com/api/1111111111111/geolookup/q/autoip.json";
URL site = new URL(website);
HttpURLConnection weatherUnderground = (HttpURLConnection) site.openConnection();
weatherUnderground.connect();
JsonParser weatherParser = new com.google.gson.JsonParser();
JsonElement weatherJson = weatherParser.parse(new InputStreamReader((InputStream) weatherUnderground.getContent()));
JsonObject weatherObj = weatherJson.getAsJsonObject();
String zip = weatherObj.get("location").getAsJsonObject().get("zip").getAsString();
String city = weatherObj.get("location").getAsJsonObject().get("city").getAsString();
String state = weatherObj.get("location").getAsJsonObject().get("state").getAsString();
String hourly = "http://api.wunderground.com/api/111111111111/hourly/q/" + state + "/" + city + ".json";
URL hourlySite = new URL(hourly);
HttpURLConnection hourlyConnection = (HttpURLConnection) hourlySite.openConnection();
hourlyConnection.connect();
com.google.gson.JsonParser hourlyParser = new com.google.gson.JsonParser();
JsonElement hourlyWeatherJson = weatherParser.parse(new InputStreamReader((InputStream) hourlyConnection.getContent()));
JsonArray weatherArr = hourlyWeatherJson.getAsJsonObject().get("hourly_forecast").getAsJsonArray();
int l = weatherArr.size();
for (int i = 0; i < l; i++) {
String date = weatherArr.get(i).getAsJsonObject().get("FCTTIME").getAsJsonObject().get("pretty").getAsString();
String temp = weatherArr.get(i).getAsJsonObject().get("temp").getAsJsonObject().get("english").getAsString();
String condition = weatherArr.get(i).getAsJsonObject().get("condition").getAsString();
String humidity = weatherArr.get(i).getAsJsonObject().get("humidity").getAsString();
String iconUrl = weatherArr.get(i).getAsJsonObject().get("icon_url").getAsString();
Bitmap icon = getBitmapFromURL(iconUrl);
data.add(new Weather(date, condition, temp, humidity, icon));
}
} catch (IOException e) {
Log.e("Error: ",e.toString());
}
return null;
}
protected void onPostExecute(Void...params){
}
}
Below are links to my screenshots showing the app not populating the listView, and the app working properly when the program is run while the phone is initially locked.
Any help would be greatly appreciated!!
Thanks
Upvotes: 0
Views: 3430
Reputation: 366
I figured out what the issue was! I hadn't added @Override to my onPostExecute() method so it was never being called.
I added the notifyDataSetChanged to my onPostExecute as suggested, which worked once I added the @override to my method.
Upvotes: 0
Reputation: 30088
In postExecute(), you need to update the adapter's List and then invoke its notifyDataSetChanged method. I suspect that you were forgetting to update the adapter's data.
The other option is to create a new adapter with the new data, and set the new adapter on the ListView.
Upvotes: 1