解决java.lang.IllegalStateException: The content of the adapter has changed but ListView...的问题

我写了一个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)]
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.widget.ListView.layoutChildren(ListView.java:1510)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.widget.AbsListView.onTouchModeChanged(AbsListView.java:2077)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.view.ViewTreeObserver.dispatchOnTouchModeChanged(ViewTreeObserver.java:591)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.view.ViewRoot.ensureTouchModeLocally(ViewRoot.java:2095)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.view.ViewRoot.performTraversals(ViewRoot.java:809)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1861)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.os.Looper.loop(Looper.java:130)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at android.app.ActivityThread.main(ActivityThread.java:3683)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at java.lang.reflect.Method.invokeNative(Native Method)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at java.lang.reflect.Method.invoke(Method.java:507)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:895)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:653)
02-21 14:54:28.928: E/AndroidRuntime(2846):     at dalvik.system.NativeStart.main(Native Method)



其中错误描述:

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 devices;

		public DeviceAdapter() {
			inflater = LayoutInflater.from(mContext);
		}

		@SuppressWarnings("unchecked")
		public void setDeviceList(ArrayList list) {
			if (list != null) {
				devices = (ArrayList) 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。


希望能帮到遇到同样问题的同学~

你可能感兴趣的:(Android)