我正在调用ASyncTask
来更新我的适配器,偶尔我在填充列表时遇到此运行时错误
E / AndroidRuntime(16197):java.lang.IllegalStateException:适配器的内容已更改,但ListView未收到通知。确保不从后台线程修改适配器的内容,而只是从UI线程修改。
从后台线程填充适配器是不是一个坏主意,如错误消息暗示的那样?
我在notifyDataSetChanged()
中呼叫onPostExecute()
,但是当我在onProgressUpdate()
中呼叫时,我也会收到同样的错误。
这是我的ASyncTask。假设fetchOneItem()从项目列表中提取单个项目,填写名称/描述,然后转到下一次迭代中的下一个项目。
private class GetItems extends AsyncTask<Integer, Integer, Integer> {
@Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(context);
pd.setTitle("Displaying...");
pd.setMessage("Please wait.");
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
TextView myMsg = (TextView)findViewById(R.id.topMsg);
myMsg.setText("Displaying items...");
}
protected Integer doInBackground(Integer... params) {
// TODO Auto-generated method stub
do {
fetchOneItem(); // fetches 1 item
myList.add(new Item(name, description));
Log.i(TAG, "Adding " + name + ", " + desc + ", adapter size = " + myAdapter.getCount());
publishProgress(i);
} while (doneFetching != true);
Log.i(TAG, "Completed loading, i =" + i);
return i;
}
protected void onProgressUpdate(Integer... values) {
TextView myMsg = (TextView)findViewById(R.id.topMsg);
myMsg.setText("Displaying " + Integer.toString(values[0].intValue()) + " items");
}
@Override
protected void onPostExecute(Integer numItems) {
TextView myMsg = (TextView)findViewById(R.id.topMsg);
myMsg.setText("Displayed " + numItems + " items");
myAdapter.notifyDataSetChanged();
allItemsLoaded = true;
Log.i(TAG, "Adapter size = " + myAdapter.getCount());
pd.dismiss();
}
}
答案 0 :(得分:0)
我可以看到您正试图“实时”更新列表视图吗?
好吧,我不知道怎么做,所以我建议你实现一个刷新按钮来调用这个AsyncTask。如果要向用户显示实际更新列表视图,则发送DialogProgress非常重要。希望它有所帮助!
答案 1 :(得分:0)
是的,你可以看到android不允许你这样做。如果要更新任何视图,则应在UI线程中执行此操作。但是你也应该永远不要在UI线程中使用慢速操作,例如android中不允许的网络通信。实际上你应该保持UI代码尽可能短,因为如果它需要太长时间,那么android会认为你的应用程序崩溃了。
编辑:我认为您正在使用ArrayAdapter,它会在您更新时通知更改。
所以你有两个选择:
使用您的ArrayAdapter,但在UI线程中更新它。
或者实现你自己的BaseAdapter子类,你做得对。
ArrayAdapter适用于简单情况,通常使用静态数据集。
答案 2 :(得分:0)
发帖迟到但可能会帮助遇到类似情况的人。
问题:您有一个长时间运行的操作,并希望将其带到后台线程。此外,操作完成后,您还要更新UI线程上的视图。
解决方案:
//spawn a new thread for background processing.
new Thread(new Runnable() {
@Override
public void run() {
//starting your background operation.
//this is a network call.
final Location location = BackendApi.builder().getSlaveLocation(mActivity.getApplicationContext(), "xyz", null);
//now i want to update views on UI thread.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//this code will run on UI thread.
myView.setText("Latitude: " + location.getLatitude());
}
});
}
}).start();
在更新视图/适配器之前,请确保未销毁活动。