Java 刷新时listView随机崩溃

Java 刷新时listView随机崩溃,java,android,listview,Java,Android,Listview,我有一个listView,每次客户端(我的android应用程序)从服务器收到消息时都会刷新,但问题是当我多次单击刷新按钮时,应用程序崩溃并向我发送此错误:java.lang.IllegalStateException:适配器的内容已更改,但listView未收到通知。确保适配器的内容不是从后台线程修改的,而是仅从UI线程修改的。确保适配器在其内容更改时调用notifyDataSetChanged()。 编辑1:崩溃不会每次都发生,只要我快速点击刷新按钮十次 活动代码: class recei

我有一个listView,每次客户端(我的android应用程序)从服务器收到消息时都会刷新,但问题是当我多次单击刷新按钮时,应用程序崩溃并向我发送此错误:
java.lang.IllegalStateException:适配器的内容已更改,但listView未收到通知。确保适配器的内容不是从后台线程修改的,而是仅从UI线程修改的。确保适配器在其内容更改时调用notifyDataSetChanged()。

编辑1:崩溃不会每次都发生,只要我快速点击刷新按钮十次

活动代码:

 class receiveimplements Runnable {
    @Override
    public void run() {
        try {

            if (socket != null && socket.isConnected()) {

                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                for (; ; ) {
                    while ((textRecu = reader.readLine()) != null) {
                        if (textRecu.length() < 6) {
                            bug = true;
                            break;
                        }

                        Log.d("textrecuapres", textRecu);
                        index++;
                        if (index == 1) {
                            listTitre.add(0, textRecu);
                            sendListeAndMakeAffichage(listSource,listTitre);
                        } else if (index == 2) {
                            listSource.add(0, textRecu);
                            index = 0;
                        }
                    }
                }
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

public void sendListeAndMakeAffichage(final List<String> sourceList,final List<String> sourceTitre) {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            fragmentListe.setListTitreAndListSource(sourceTitre, sourceList);

        }
    });

}
class receiveimplements可运行{
@凌驾
公开募捐{
试一试{
if(socket!=null&&socket.isConnected()){
BufferedReader=新的BufferedReader(新的InputStreamReader(socket.getInputStream());
对于(;;){
而((textrec=reader.readLine())!=null){
if(textrec.length()<6){
bug=true;
打破
}
Log.d(“textrecapres”,textrecure);
索引++;
如果(索引==1){
添加(0,textRecu);
SendListendMakeAffichage(列表源、列表标题);
}else if(索引==2){
添加(0,textrec);
指数=0;
}
}
}
}
}捕获(未知后异常e){
e、 printStackTrace();
}捕获(IOE异常){
e、 printStackTrace();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
public void sendliste和makeAffichage(最终列表源列表,最终列表源标题){
runOnUiThread(新的Runnable(){
@凌驾
公开募捐{
FragmentList.setListTitreAndListSource(sourceTitre,sourceList);
}
});
}
Listfragment代码:

public void setListTitreAndListSource(List<String> listTitre, List<String> listSource) {

    this.listTitre = listTitre;
    this.listSource = listSource;

    adapter.bind(listTitre);
    setListAdapter(adapter);
}
public void setListTitreAndListSource(List listTitre,List listSource){
this.listTitre=listTitre;
this.listSource=listSource;
适配器绑定(列表标题);
setListAdapter(适配器);
}
适配器代码:

  public void bind(List<String> model) {
    notifyDataSetChanged();
    listeTitre = model;
    notifyDataSetChanged();
}
公共无效绑定(列表模型){
notifyDataSetChanged();
李斯特=模型;
notifyDataSetChanged();
}

正如错误消息通知您的那样,您不能从非UI线程修改UI元素(并且您的
可运行
使用单独的线程)


使用
处理程序
更新UI线程。查看此答案,例如:

当您添加到
列表标题时,不调用
notifyDataSetChanged()

这将更改适配器的内容。您确实安排了对
notifyDataSetChanged()
的调用,但是不能保证在ListView的呈现(将验证其状态)之前安排调用。适配器必须在与
notifyDataSetChanged()
调用相同的已处理消息中进行操作,以确保在下一次渲染中同时发生

所以现在你正在做:

线程-1: 添加到列表中

主线程: evaluatePendingMessages([validate ListView,runnable,调用
notifyDataSetChanged()
]

您必须在更新适配器的部件所在的同一事件中修改适配器(并且它们都必须从主线程根目录)

所以如果你的逻辑是正确的,你应该这样做

  if (index == 1) {
     sendListeAndMakeAffichage(listSource,listTitre, textRecu);
  } ....
然后在该方法内部:

public void sendListeAndMakeAffichage(final List<String> sourceList,final List<String> sourceTitre, final String newEntry) {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            listTitre.add(newEntry); // Now we manipulate the list in this runnable
            // While the next call to the fragment will finish updating the adapter
            // and call notifyDataSetChanged()
            fragmentListe.setListTitreAndListSource(sourceTitre, sourceList);

        }
    });

}
public void sendliste和makeAffichage(最终列表sourceList、最终列表sourceTitre、最终字符串newEntry){
runOnUiThread(新的Runnable(){
@凌驾
公开募捐{
add(newEntry);//现在我们在这个runnable
//而对片段的下一次调用将完成对适配器的更新
//并调用notifyDataSetChanged()
FragmentList.setListTitreAndListSource(sourceTitre,sourceList);
}
});
}

我遇到了与以前相同的错误,我忘了说崩溃不是每次都会发生,它只是在我快速单击刷新按钮大约十次时才会发生,所以您建议我添加notifyDataSetChanged();此处?
public void sendliste和makeAffichage(最终列表源列表,最终列表源标题){rununuithread(new Runnable(){@Override public void run(){fragmentListe.setListTitreAndListSource(sourceTitre,sourceList);}});
No您已经在
fragment.Liste.setListTier..中执行了此操作。);
我是说你必须在同一个Runnable中执行添加和notifyDataSetChanged。你的textRecu应该添加到UIThread上的同一个Runnable中。非常感谢你的帮助:)它可以工作,我不知道我曾经在UI线程中操纵列表
public void sendListeAndMakeAffichage(final List<String> sourceList,final List<String> sourceTitre, final String newEntry) {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            listTitre.add(newEntry); // Now we manipulate the list in this runnable
            // While the next call to the fragment will finish updating the adapter
            // and call notifyDataSetChanged()
            fragmentListe.setListTitreAndListSource(sourceTitre, sourceList);

        }
    });

}