我写了一个Dialog,Dialog中有一个ListView,想要点ListView中的一项后,跳转到另外一个Activity去。
但在使用时,会偶尔报出下面的错误:
02-21 14:54:28.928: E/AndroidRuntime(2846): FATAL EXCEPTION: main
02-21 14:54:28.928: E/AndroidRuntime(2846): 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. [in ListView(2131165196, class android.widget.ListView) with Adapter(class com.jovision.multiscreen.views.DeviceScanSelectDialog$DeviceAdapter)]
其中错误描述:
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.
的意思大体是,你的adapter的内容变化了,但是你的ListView并不知情。请保证你adapter的数据在主线程中进行更改!
知道了原因,改起来就好办多了,我将我的adapter类改为:
private class DeviceAdapter extends BaseAdapter { private LayoutInflater inflater; private ArrayList<Device> devices; public DeviceAdapter() { inflater = LayoutInflater.from(mContext); } @SuppressWarnings("unchecked") public void setDeviceList(ArrayList<Device> list) { if (list != null) { devices = (ArrayList<Device>) list.clone(); notifyDataSetChanged(); } } public void clearDeviceList() { if (devices != null) { devices.clear(); } notifyDataSetChanged(); } @Override public int getCount() { return devices == null ? 0 : devices.size(); } (以下略)
相对于原来,我做了两项改动:
1.将所有数据“完全”保存在adapter内部,即使有外部数据进入,也会用.clone()重新生成副本,保证了数据完全是由adapter维护的。
2.保证所有setDeviceList()/clearDeviceList()是从主线程里调用的,如何保证是从主线程中调用的呢:
a.调用Activity.runOnUIThread()方法;
b.使用Handler(其实这并不非常准确,因为Handler也可以运行在非UI线程);
c.使用AsyncTask。
希望能帮到遇到同样问题的同学~