我有一个普通的listview / listadapter,我正在使用AsyncTask从网络加载大量数据。完全下载并解析所有数据大约需要5秒钟。
我在处理数据时没有将listview清空5秒,而是希望在处理数据时对其进行更新,以便用户在准备好时可以查看并滚动列表项。处理每件物品需要大约20-50毫秒,并准备好展示。
有人可以帮我解决一下如何实现这一目标。
我试过这段代码只刷新每500毫秒。当新项目处理完毕后,我每隔20到50ms从AsyncTask调用onNewItemReady():
public void onNewItemReady(Object item) {
mData.add(item);
long diff = SystemClock.elapsedRealtime()-mLastRefresh;
if (diff > 500) {
mAdapter.setData(mData);
mAdapter.notifyDataSetChanged();
mLastRefresh = SystemClock.elapsedRealtime();
}
}
但如果我在加载所有数据之前滚动列表视图,则会收到以下错误:
> 05-04 19:22:59.638: E/AndroidRuntime(24349):
> java.lang.IllegalStateException: The content of the adapter has
> changed but ListView did not receive a notification. Make sure the
> content of your adapter is not modified from a background thread, but
> only from the UI thread. Make sure your adapter calls
> notifyDataSetChanged() when its content changes. [in
> ListView(16908298, class android.widget.ListView) with Adapter(class
> MyAdapter)]
谢谢!
编辑:我没有从后台线程刷新适配器。正在从AsyncTask的onProgressPublished中调用onNewItemReady()。
答案 0 :(得分:0)
正如logcat消息所示,您正在尝试从后台线程(可能是AsyncTask)刷新listview(在UI线程上),所以您需要做的就是在完成doInbackground()
的执行后AsyncTask,您应该刷新asynctask的onPostExecute()
中的列表视图。
为了避免用户在下载过程中进行互动,您应该在onPreexcecute()
中显示进度对话框。
所以你的Asynctask应该是这样的:
class YourAsyncTask extends AsyncTask{
ProgressDialog pd;
onPreExecute(){
// show progress dialog here..
}
doInBackground(){
// perform network operation here and collect collect data
}
onPostExecute(){
// dismiss dialog box.
// refresh listview
}
}
请注意,这只是代码的蓝图,正确的语法请参考this
<强>替代强>
另外,正如您所说的那样,您正在加载大量数据并且需要大约5秒钟(这是很多时间),建议使用Pull-to-refresh
,因为它将load data on demand
。你可以google它,那里有很多东西。
答案 1 :(得分:0)
我正在使用&#34;无尽的适配器&#34;并显示添加的#34; loading&#34;当用户滚动到底部时,在我的列表视图底部查看。我从Google i / o 2013应用程序中获取了我使用的代码。显然这段代码导致了这个问题。我已经删除它并用更简单的footerview替换它,问题已经消失。
这是我在适配器中使用的代码:
@Override
public int getCount() {
if (mData != null) {
return mData.size() + (
((mDataTask.isLoading()) // we are already loading
|| mDataTask.hasMoreResults() // or there are more results
|| mDataTask.isErrored()) // or there's an error
? 1 : 0);
}
return 0;
}
而不是这段代码,我只是在开始加载时添加一个footerview,并在onPostExecute完成时将其删除。