Android自定义适配器和asyncTask不更新listView
Posted
技术标签:
【中文标题】Android自定义适配器和asyncTask不更新listView【英文标题】:Android custom adapter and asyncTask not updating listView 【发布时间】:2015-05-02 03:34:41 【问题描述】:我搜索了所有我能找到的帖子,但似乎没有一个对我的情况有帮助。我有一个 android 项目,它使用 Web 服务来提取每小时的天气数据并用结果填充 listView。
我遇到的奇怪问题是,当我在我的 android 手机上调试项目时,主要活动是空白的,并且没有填充 listView。如果我在手机锁定的情况下从 android studio 运行项目,然后解锁手机,则应用会在我的手机上打开,并且所有 listView 都已正确格式化和填充。
我觉得这是 asynctask 和适配器之间的竞争条件问题,但我似乎无法解决它。我尝试将我的 asyncTask 设为内部私有类并在 onPostExecute
方法内的适配器上调用 notifyDataSetChanged
,但无济于事。我觉得这一定很简单,但我对 Android 开发人员比较陌生,所以我被卡住了。
我有三个课程,我将从中发布相关代码
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;
下载WeatherTask.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)
以下是我的屏幕截图链接,显示应用程序未填充 listView,并且在手机最初锁定时运行程序时应用程序正常工作。
任何帮助将不胜感激!
谢谢
【问题讨论】:
【参考方案1】:在 postExecute() 中,您需要更新适配器的 List,然后调用其 notifyDataSetChanged 方法。我怀疑您忘记更新适配器的数据。
另一个选项是使用新数据创建一个新适配器,并在 ListView 上设置新适配器。
【讨论】:
我不确定如何从 asyncTask 访问适配器。我尝试将 Async 类设为子类并以这种方式进行操作,并将其作为参数传递给我的 async 类,但均未奏效。 我会将它传递给 AsyncTask 的构造函数【参考方案2】:我发现了问题所在!我没有将 @Override 添加到我的 onPostExecute() 方法中,所以它永远不会被调用。
我按照建议将 notifyDataSetChanged 添加到我的 onPostExecute 中,一旦我将 @override 添加到我的方法中,它就起作用了。
【讨论】:
以上是关于Android自定义适配器和asyncTask不更新listView的主要内容,如果未能解决你的问题,请参考以下文章
如何从android中的自定义适配器调用Activity asynctask
Asynctask 和 RecyclerView 适配器中的 Android ProgressDialog