简体   繁体   English

刷新时listView随机崩溃

[英]listView crashed randomly when refresh

I have a listView whixh is refresh each time the client (my android app) receive a message from the server but the problem is when i click to many time on the refresh button the app crash and send me this error: 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. 每当客户端(我的android应用)从服务器收到消息时,我都有一个listView刷新,但是问题是,当我在刷新按钮上单击很多次时,应用崩溃,并向我发送此错误: 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. 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.

edit 1: the crash does not happen every time it onlu happen when i click about ten times quickly on the refresh button 编辑1:当我在刷新按钮上快速单击大约十次时,崩溃不会在每次发生时发生

activity code: 活动代码:

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

        }
    });

}

Listfragment code: Listfragment代码:

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

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

    adapter.bind(listTitre);
    setListAdapter(adapter);
}

adapter code: 适配器代码:

  public void bind(List<String> model) {
    notifyDataSetChanged();
    listeTitre = model;
    notifyDataSetChanged();
}

When you add to listTitre , without calling notifyDataSetChanged() 当您添加到listTitre ,无需调用notifyDataSetChanged()

  if (index == 1) {
     listTitre.add(0, textRecu);
     sendListeAndMakeAffichage(listSource,listTitre);

This is changing the contents of the adapter. 这正在更改适配器的内容。 You do schedule a call to notifyDataSetChanged() however it is not guaranteed to be scheduled before the ListView's render which will validate it's state. 您确实安排了对notifyDataSetChanged()的调用,但是并不能保证将其安排在ListView的呈现器之前进行,以验证其状态。 The adapter has to be manipulated within the same handled message as the notifyDataSetChanged() call in order to guarantee it all happens at once in the next render. 必须确保在与notifyDataSetChanged()调用相同的已处理消息中处理适配器,以确保适配器在下一次呈现时立即发生。

So right now you are doing: 所以现在您正在做:

Thread-1: Add to List 线程-1:添加到列表

Main Thread : evaluatePendingMessages([validate ListView, runnable which calls notifyDataSetChanged() ] 主线程: notifyDataSetChanged() [验证ListView,运行notifyDataSetChanged() runnable]

You have to modify the adapter within the same event as the part that updates the adapter (And they both have to root from the main thread) 您必须在与更新适配器的部分相同的事件中修改适配器(而且它们都必须从主线程中启动)

So if this is valid with your logic you should do this. 因此,如果这在您的逻辑上有效,则应执行此操作。

  if (index == 1) {
     sendListeAndMakeAffichage(listSource,listTitre, textRecu);
  } ....

Then inside of that method: 然后在该方法内部:

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

        }
    });

}

As the error message informs you, you cannot modify UI elements from a non-UI thread (and your Runnable uses a separate thread). 如错误消息所通知,您不能从非UI线程修改UI元素(您的Runnable使用单独的线程)。

Use a Handler to update the UI thread. 使用Handler程序更新UI线程。 See this answer, for example: https://stackoverflow.com/a/12717105/240646 参见以下答案,例如: https : //stackoverflow.com/a/12717105/240646

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM