我有活动,我在listView中查看数据。但我必须从另一个线程填充数据。正如您在以下代码中看到的那样。在每次数据更改时,我都在调用处理器消息,触发notifyDataSetChanged()。当我更新每秒少于1次更改的数据时,它可以正常工作,但是当我更快地更改数据时它会抛出IllegalStateException。有没有机会抓住这个例外?
有没有更明确的解决方案如何从另一个线程更新数据?
完整代码链接:https://www.dropbox.com/s/nxyac1xd88g2y71/TestListThreadFill.zip
的活动:
public class MainActivity extends Activity {
private ListView list;
private TestAdapter adapter;
public static MainActivity magic;
/**
* Called when the activity is first created.
*/
@Override public void onCreate( Bundle savedInstanceState) {
magic = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list = (ListView)findViewById( R.id.list);
adapter = new TestAdapter( getApplicationContext());
new FillThread().execute((Object) null);
Data.getInstance().addHandler(this, new Handler(){
@Override public void dispatchMessage(Message msg) {
update();
super.dispatchMessage(msg);
}
});
}
public void update(){
adapter.notifyDataSetChanged();
}
@Override protected void onResume() {
list.setAdapter( adapter);
super.onResume();
}
}
Data continer:
public class Data extends Vector<DataItem> {
private static Data instance = null;
private HashMap< Object, Handler> handlerList;
public Data() {
handlerList = new HashMap< Object, Handler>();
}
public static Data getInstance(){
if( instance == null)
instance = new Data();
return instance;
}
@Override public synchronized boolean add( DataItem object) {
boolean result = super.add(object);
for( Map.Entry< Object, Handler> handler : handlerList.entrySet())
{
handler.getValue().sendEmptyMessage( 0);
}
return result;
}
public synchronized void addHandler( Object object, Handler handler){
handlerList.put( object, handler);
}
public synchronized void addHandler( Handler handler){
addHandler( handler, handler);
}
public synchronized void removeHandler( Object object){
handlerList.remove( object);
}
}
数据填充线程:
public class FillThread extends AsyncTask{
@Override protected Object doInBackground(Object... params) {
while( true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Data.getInstance().add( new DataItem( "L", "TOP", "BOTTOM"));
}
}
}
logcat的:
05-23 13:20:23.900 25260-25260/com.example.TestListThreadFill E/AndroidRuntime﹕ FATAL EXCEPTION: main
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(2131034115, class android.widget.ListView) with Adapter(class com.example.TestListThreadFill.TestAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1549)
at android.widget.AbsListView.onLayout(AbsListView.java:2170)
at android.view.View.layout(View.java:13846)
at android.view.ViewGroup.layout(ViewGroup.java:4466)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1649)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1507)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1420)
at android.view.View.layout(View.java:13846)
at android.view.ViewGroup.layout(ViewGroup.java:4466)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:13846)
at android.view.ViewGroup.layout(ViewGroup.java:4466)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1649)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1507)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1420)
at android.view.View.layout(View.java:13846)
at android.view.ViewGroup.layout(ViewGroup.java:4466)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:13846)
at android.view.ViewGroup.layout(ViewGroup.java:4466)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2149)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1907)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1127)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4606)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:747)
at android.view.Choreographer.doCallbacks(Choreographer.java:567)
at android.view.Choreographer.doFrame(Choreographer.java:536)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:733)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:153)
at android.app.ActivityThread.main(ActivityThread.java:4987)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
at dalvik.system.NativeStart.main(Native Method)
05-23 13:20:30.923 25260-25265/com.example.TestListThreadFill D/jdwp﹕ processIncoming
05-23 13:20:30.923 25260-25265/com.example.TestListThreadFill D/jdwp﹕ handlePacket : cmd=0x1, cmdSet=0xC7, len=0x13, id=0x4000016E, flags=0x0, dataLen=0x8
05-23 13:20:31.421 25260-25265/com.example.TestListThreadFill D/jdwp﹕ processIncoming
05-23 13:20:31.421 25260-25265/com.example.TestListThreadFill D/jdwp﹕ handlePacket : cmd=0x1, cmdSet=0xC7, len=0x17, id=0x4000016F, flags=0x0, dataLen=0xC
05-23 13:20:31.429 25260-25265/com.example.TestListThreadFill D/jdwp﹕ processIncoming
05-23 13:20:31.429 25260-25265/com.example.TestListThreadFill D/jdwp﹕ handlePacket : cmd=0x1, cmdSet=0xC7, len=0x13, id=0x40000170, flags=0x0, dataLen=0x8
05-23 13:20:31.429 25260-25265/com.example.TestListThreadFill D/jdwp﹕ processIncoming
05-23 13:20:31.429 25260-25265/com.example.TestListThreadFill D/jdwp﹕ handlePacket : cmd=0x1, cmdSet=0xC7, len=0x13, id=0x40000171, flags=0x0, dataLen=0x8
答案 0 :(得分:0)
很明显错误信息:
Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.
您可以尝试这样的事情:
public class FillThread extends AsyncTask<Void, Void, DataItem> {
@Override
protected DataItem doInBackground(Void... params) {
return new DataItem();
}
@Override
protected void onPostExecute(DataItem dataItem) {
// call an update method that adds the dataItem and notifies the adapter
}
}