简体   繁体   中英

Android custom adapter and asyncTask not updating listView

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.

http://i57.tinypic.com/i55b0n.png http://i62.tinypic.com/rho477.png

Any help would be greatly appreciated!!

Thanks

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM