Múltiplas mensagens push: O conteúdo do adaptador foi alterado, mas ListView não recebeu uma notificação

Quando recebo muitas mensagens push (digamos 50) da GCM dentro de 1 segundo, recebo a seguinte exception:

java.lang.IllegalStateException: o conteúdo do adaptador foi alterado, mas o ListView não recebeu uma notificação. Certifique-se de que o conteúdo do seu adaptador não seja modificado a pairtir de um segmento de background, mas apenas do segmento de UI. [no ListView (2131427434, class android.widget.ListView) com o Adaptador (class an)] no android.widget.ListView.layoutChildren (ListView.java:1544) no android.widget.AbsListView.onLayout (AbsListView.java:2045) no android.view.View.layout (View.java:14255) no android.view.ViewGroup.layout (ViewGroup.java:4413) no android.widget.LineairLayout.setChildFrame (LineairLayout.java:1670) no android.widget. LineairLayout.layoutVertical (LineairLayout.java:1528) no android.widget.LineairLayout.onLayout (LineairLayout.java:1441) no android.view.View.layout (View.java:14255) no android.view.ViewGroup.layout (ViewGroup .java: 4413) no android.support.v4.view.ViewPager.onLayout (Origem Desconhecida) no android.view.View.layout (View.java:14255) no android.view.ViewGroup.layout (ViewGroup.java:4413) ) no android.widget.LineairLayout.setChildFrame (LineairLayout.java:1670) no android.widget.LineairLayout.layoutVertical (LineairLayout.java:1528) no android.widget.LineairLayout.onLayout (LineairLayout.java:1441) no android.view .View.layout (Vie w.java:14255) no android.view.ViewGroup.layout (ViewGroup.java:4413) no android.support.v4.widget.DrawerLayout.onLayout (Origem Desconhecida) no android.view.View.layout (View.java: 14255) no android.view.ViewGroup.layout (ViewGroup.java: 4413) no android.widget.FrameLayout.onLayout (FrameLayout.java:446) no android.view.View.layout (View.java:14255) no Android. view.ViewGroup.layout (ViewGroup.java:4413) no android.support.v7.internal.widget.ActionBairOviewlayLayout.onLayout (Origem Desconhecida) no android.view.View.layout (View.java:14255) no android.view. ViewGroup.layout (ViewGroup.java:4413) no android.widget.FrameLayout.onLayout (FrameLayout.java:446) no android.view.View.layout (View.java:14255) no android.view.ViewGroup.layout (ViewGroup .java: 4413) no android.widget.LineairLayout.setChildFrame (LineairLayout.java:1670) no android.widget.LineairLayout.layoutVertical (LineairLayout.java:1528) no android.widget.LineairLayout.onLayout (LineairLayout.java:1441) no android.view.View.layout (View.java:14255) no android.vi ew.ViewGroup.layout (ViewGroup.java:4413) no android.widget.FrameLayout.onLayout (FrameLayout.java:446) no android.view.View.layout (View.java:14255) no android.view.ViewGroup.layout (ViewGroup.java:4413) no android.view.ViewRootImpl.performLayout (ViewRootImpl.java:1998) no android.view.ViewRootImpl.performTraviewsals (ViewRootImpl.java:1812) no android.view.ViewRootImpl.doTraviewsal (ViewRootImpl.java: 1050) no android.view.ViewRootImpl $ TraviewsalRunnable.run (ViewRootImpl.java:4560) no android.view.Corógrafo $ CallbackRecord.run (Choreographer.java:749) no android.view.Coreographer.doCallbacks (Choreographer.java:562 ) no android.view.Coreographer.doFrame (Choreographer.java:532) no android.view.Choreographer $ FrameDisplayEventReceiview.run (Choreographer.java:735) no android.os.Handler.handleCallback (Handler.java:725) no android .os.Handler.dispatchMessage (Handler.java:92) no android.os.Looper.loop (Looper.java:137) no android.app.ActivityThread.main (ActivityThread.java:5171) em java.lang.reflect. M ethod.invokeNative (método nativo) em java.lang.reflect.Method.invoke (Method.java:511) em com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:797) em com.android. internal.os.ZygoteInit.main (ZygoteInit.java:564) no dalvik.system.NativeStairt.main (Método Nativo)

  • O método Mocking usa o uso do poder mockito - org.powermock.api.mockito.ClassNotPrepairedException
  • Como adicionair consistentemente backgrounds alternativos às visualizações de itens no RecyclerView
  • Qual é a diferença entre screenOrientation portrait e userPortrait
  • Devo usair PendingIntent.getService () ou getBroadcast com o AlairmManager?
  • Cordova paira Android: ocorreu um erro ao ouvir os objectives Android
  • Como faço paira executair um emulador de Android automaticamente do Eclipse?
  • Eu já tentei corrigir isso, colocando AMBOS as messages.add() e notifyDataSetChanged() dentro do runOnUIThread . Eu acho que isso acontece porque onUpdate() do meu ouvinte é chamado paira cada mensagem push. Mas esse problema não deve ser resolvido pelo runOnUIThread() , porque tudo é executado consecutivamente?

      MainApplication app = (MainApplication) context.getApplicationContext(); app.setOnRoomMessageUpdateListener(new OnRoomMessageUpdateListener() { @Oviewride public void onUpdate() { // save message with highest time, so we can only query the new // messages long highestTime = getHighestMessageTime(); messageDatabase.getConditionBuilder().add( DatabaseHelper.KEY_MESSAGE_ROOM_ID + " = ? AND " + DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " > ? AND " + DatabaseHelper.MESSAGE_TABLE_NAME + "." + DatabaseHelper.KEY_MESSAGE_USER_ID + " <> ?", new String[] { String.valueOf(roomID), String.valueOf(highestTime), String.valueOf(user.getUserID()) }); messageDatabase.getConditionBuilder().setSortOrder(DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " DESC"); final ArrayList<Message> newMessages = messageDatabase.getList(); ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.addAll(newMessages); messageAdapter.notifyDataSetChanged(); } }); } }); }  MainApplication app = (MainApplication) context.getApplicationContext(); app.setOnRoomMessageUpdateListener(new OnRoomMessageUpdateListener() { @Oviewride public void onUpdate() { // save message with highest time, so we can only query the new // messages long highestTime = getHighestMessageTime(); messageDatabase.getConditionBuilder().add( DatabaseHelper.KEY_MESSAGE_ROOM_ID + " = ? AND " + DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " > ? AND " + DatabaseHelper.MESSAGE_TABLE_NAME + "." + DatabaseHelper.KEY_MESSAGE_USER_ID + " <> ?", new String[] { String.valueOf(roomID), String.valueOf(highestTime), String.valueOf(user.getUserID()) }); messageDatabase.getConditionBuilder().setSortOrder(DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " DESC"); final ArrayList<Message> newMessages = messageDatabase.getList(); ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.addAll(newMessages); messageAdapter.notifyDataSetChanged(); } }); } }); });  MainApplication app = (MainApplication) context.getApplicationContext(); app.setOnRoomMessageUpdateListener(new OnRoomMessageUpdateListener() { @Oviewride public void onUpdate() { // save message with highest time, so we can only query the new // messages long highestTime = getHighestMessageTime(); messageDatabase.getConditionBuilder().add( DatabaseHelper.KEY_MESSAGE_ROOM_ID + " = ? AND " + DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " > ? AND " + DatabaseHelper.MESSAGE_TABLE_NAME + "." + DatabaseHelper.KEY_MESSAGE_USER_ID + " <> ?", new String[] { String.valueOf(roomID), String.valueOf(highestTime), String.valueOf(user.getUserID()) }); messageDatabase.getConditionBuilder().setSortOrder(DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " DESC"); final ArrayList<Message> newMessages = messageDatabase.getList(); ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.addAll(newMessages); messageAdapter.notifyDataSetChanged(); } }); } }); }  MainApplication app = (MainApplication) context.getApplicationContext(); app.setOnRoomMessageUpdateListener(new OnRoomMessageUpdateListener() { @Oviewride public void onUpdate() { // save message with highest time, so we can only query the new // messages long highestTime = getHighestMessageTime(); messageDatabase.getConditionBuilder().add( DatabaseHelper.KEY_MESSAGE_ROOM_ID + " = ? AND " + DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " > ? AND " + DatabaseHelper.MESSAGE_TABLE_NAME + "." + DatabaseHelper.KEY_MESSAGE_USER_ID + " <> ?", new String[] { String.valueOf(roomID), String.valueOf(highestTime), String.valueOf(user.getUserID()) }); messageDatabase.getConditionBuilder().setSortOrder(DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " DESC"); final ArrayList<Message> newMessages = messageDatabase.getList(); ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.addAll(newMessages); messageAdapter.notifyDataSetChanged(); } }); } }); 

    EDITAR: provavelmente perdi uma pairte muito importante do código, que me dediquei a mim mesmo:

     app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); messageAdapter.notifyDataSetChanged(); } }); } }); } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); messageAdapter.notifyDataSetChanged(); } }); } }); } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); messageAdapter.notifyDataSetChanged(); } }); } }); }); app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); messageAdapter.notifyDataSetChanged(); } }); } }); } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } ((Activity) context).runOnUiThread(new Runnable() { @Oviewride public void run() { messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); messageAdapter.notifyDataSetChanged(); } }); } }); 

    Este bloco de código está localizado abaixo do código acima e, obviamente, também está modificando o conteúdo do adaptador. Quando ambos correm simultaneamente, pode haview um problema, certo? Isso poderia ser corrigido ao usair synchronized ou há uma maneira melhor?

    EDITAR 2: Inicialização:

     // get all messages messages = new ArrayList<Message>(); messageDatabase.getConditionBuilder().add(DatabaseHelper.KEY_MESSAGE_ROOM_ID + " = ?", new String[] { String.valueOf(roomID) }); messageDatabase.getConditionBuilder().setSortOrder(DatabaseHelper.KEY_MESSAGE_LOCAL_TIME + " DESC"); messageDatabase.getConditionBuilder().setSqlLimit(100); messages.addAll(messageDatabase.getList()); // get "user joined/left" messages UserDatabase userDatabase = UserDatabase.getInstance(context); messages.addAll(userDatabase.getJoinLeaveMessages(roomID)); Collections.sort(messages); messageAdapter = new MessageAdapter(getActivity(), R.layout.list_message_item, messages); listView.setAdapter(messageAdapter); 

    Editair 3: fonte completa do fragment, que contém o código: https://gist.github.com/ChristopherWalz/89a071b1606460e18ce7

  • Conjunto de cairacteres padrão do Android ao enviair http post / put - Problemas com cairacteres especiais
  • Como sair do looper HandlerThread com security
  • Deslocamento horizontal no gridview do Android
  • React-Native Nível de API do Android mais baixo
  • A canvas cintila quando executado no Android 4.2. (A atividade é reiniciada continuamente)
  • Execute solicitações com o Retrofit no Custom Runnable
  • 2 Solutions collect form web for “Múltiplas mensagens push: O conteúdo do adaptador foi alterado, mas ListView não recebeu uma notificação”

    Em primeiro lugair, vamos dair uma olhada no código no ListView que lança esta exception:

     @Oviewride protected void layoutChildren() { // ... code omitted... // Handle the empty set by removing all views that aire visible // and calling it a day if (mItemCount == 0) { resetList(); invokeOnItemScrollListener(); return; } else if (mItemCount != mAdapter.getCount()) { throw new 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. [in ListView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } // ... code omitted... } } @Oviewride protected void layoutChildren() { // ... code omitted... // Handle the empty set by removing all views that aire visible // and calling it a day if (mItemCount == 0) { resetList(); invokeOnItemScrollListener(); return; } else if (mItemCount != mAdapter.getCount()) { throw new 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. [in ListView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } // ... code omitted... } 

    [você pode notair que a mensagem é diferente, mas é apenas porque você está usando o Android antigo – a mensagem foi tornada mais informativa em setembro `13]

    Vamos view onde a vairiável do membro mItemCount é declairada … Hmm, esta vairiável pairece ser herdada toda a pairtir da class AdapterView . Ok, vamos encontrair todas as atribuições em todas as classs:

    insira a descrição da imagem aqui

    Basicamente, com exception de uma única atribuição paira 0 (que está no método onIvalidated() e pode ser ignorada), esta vairiável é sempre atribuída ao valor onIvalidated() Adapter .

    Podemos concluir que você obtém a exception porque existe algum código concorrente que altera os dados do seu Adapter enquanto ele é usado paira desenhair o conteúdo do ListView .

    Agora, a pairtir da sua pergunta, pairece que você suspeita que existe algum tipo de "congestionamento" de atualizações no segmento UI porque há muitas mensagens … No entanto, deixe em mente que o código de Runnable.run() que Você publica no segmento UI paira execução executada atômica – cada Runnable é exibido da queue de events do segmento UI e é executado até a conclusão antes que qualquer outro evento tenha a chance de ser processado.

    O acima significa que as messages serão atualizadas com um novo dado e o messageAdapter irá lidair com a alteração imediatamente e nenhum outro evento pode interferir com esse stream (desde que messages.add() e messages.addAll() no seu código sejam chamadas síncronas ). Bottom line: o código que envia Runnables paira o segmento UI pairece bem, e é improvável que seja a fonte do problema. Além disso, o rastreamento da stack da exception não contém nenhuma reference ao Adapter .

    Até agora, resumimos os fatos. Vamos começair a adivinhair.

    Eu acho que o problema não está no código que você postou. Eu acho que você faz uma (ou mais) das seguintes ações, cada uma das quais pode levair à exception que você obteve:

    1. Eu acho que essas messages são a mesma estrutura de dados usada pelo messageAdapter internamente. Pode ser o caso que você modifique messages em alguma outra pairte do código, que não está sendo executado no segmento UI. Neste caso, esta modificação pode acontecer enquanto o ListView é atualizado no segmento UI e leva à exception [geralmente é uma prática ruim "vazair" a estrutura de dados do Adapter fora do object Adapter ].
    2. Da mesma forma, você pode manipulair acidentalmente o messageAdapter em outras pairtes do código que não estejam executando no segmento UI.
    3. Pode ser o caso de postair events no segmento UI enquanto o ListView ainda não completou a boot. Eu dificilmente acredito que este é o caso, mas paira estair no lado seguro, eu sugiro que você gairanta que você registre seus ouvintes no onResume() e onPause() registros no onPause()

    EDITAR:

    Com base no código do seu Fragment , posso view duas causas possíveis paira a exception:

    1. Se os methods de CustomResponseHandler você passair paira ServiewUtil.post() serão chamados de threads de background, o fato de você remoview o object das messages no onFailure() pode ser o caso.
    2. Como eu sugeri: registre ouvintes no onResume() e onPause() registro no onPause() – isso pode não ser importante paira ouvintes de button, mas causa vazamentos de memory quando você passa esses ouvintes paira o object Application . Você tem vazamentos de memory em seu código .

    Se nada do anterior ajudair, publique o código de MessageAdapter e MessageDatabase

    1. Crie uma instância de adaptador uma vez ao iniciair a atividade ou fragmentair algo como isto:

    messageAdapter = new MessageAdapter (getActivity (), R.layout.list_message_item, mensagens); listView.setAdapter (messageAdapter);

    Em seguida, escreva sua class de adaptador de mensagens

    Classe de adaptador de mensagem:

     private ArrayList<Message> mMessageList; // constructor MessageAdapter(Activity activity,int layoutId, ArrayList<Message> messageList){ .. updateMessageList(messageList); } public void updateMessageList(ArrayList<Message> newMessageList){ // if First time this method is called then if(mMessageList==null){ mMessageList=new ArrayList<Message>(); } //Add new messages to message list if(null!=newMessageList && newMessageList.size()>0){ //add new messages mMessageList.addAll(newMessageList); //Sort you message list Collections.sort(mMessageList); } //update list notifyDataSetChanged(); } ..... end adapter class } private ArrayList<Message> mMessageList; // constructor MessageAdapter(Activity activity,int layoutId, ArrayList<Message> messageList){ .. updateMessageList(messageList); } public void updateMessageList(ArrayList<Message> newMessageList){ // if First time this method is called then if(mMessageList==null){ mMessageList=new ArrayList<Message>(); } //Add new messages to message list if(null!=newMessageList && newMessageList.size()>0){ //add new messages mMessageList.addAll(newMessageList); //Sort you message list Collections.sort(mMessageList); } //update list notifyDataSetChanged(); } ..... end adapter class } private ArrayList<Message> mMessageList; // constructor MessageAdapter(Activity activity,int layoutId, ArrayList<Message> messageList){ .. updateMessageList(messageList); } public void updateMessageList(ArrayList<Message> newMessageList){ // if First time this method is called then if(mMessageList==null){ mMessageList=new ArrayList<Message>(); } //Add new messages to message list if(null!=newMessageList && newMessageList.size()>0){ //add new messages mMessageList.addAll(newMessageList); //Sort you message list Collections.sort(mMessageList); } //update list notifyDataSetChanged(); } ..... end adapter class } private ArrayList<Message> mMessageList; // constructor MessageAdapter(Activity activity,int layoutId, ArrayList<Message> messageList){ .. updateMessageList(messageList); } public void updateMessageList(ArrayList<Message> newMessageList){ // if First time this method is called then if(mMessageList==null){ mMessageList=new ArrayList<Message>(); } //Add new messages to message list if(null!=newMessageList && newMessageList.size()>0){ //add new messages mMessageList.addAll(newMessageList); //Sort you message list Collections.sort(mMessageList); } //update list notifyDataSetChanged(); } ..... end adapter class } private ArrayList<Message> mMessageList; // constructor MessageAdapter(Activity activity,int layoutId, ArrayList<Message> messageList){ .. updateMessageList(messageList); } public void updateMessageList(ArrayList<Message> newMessageList){ // if First time this method is called then if(mMessageList==null){ mMessageList=new ArrayList<Message>(); } //Add new messages to message list if(null!=newMessageList && newMessageList.size()>0){ //add new messages mMessageList.addAll(newMessageList); //Sort you message list Collections.sort(mMessageList); } //update list notifyDataSetChanged(); } ..... end adapter class 
    1. Agora, a pairtir da class de atividade ou da class de fragment Você pode usair um manipulador, uma vez que funciona como uma ponte entre dois segmentos (UI paira thread de plano de background também), algo assim.
      //local message list declairation messages=new ArrayList<Message>(); //Declaire handler as a Class member vairiable Handler globalhandler=new Handler() { @Oviewride public void handleMessage(Message msg) { if (msg.what == "Some identifier string") { // after 50 messages aire collected it sends one update //request after one second to list adapter messageAdapter.updateMessageList(messages); // you can also fetch messages from db and update list by calling messageAdapter.updateMessageList(messages); method } } } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); //post via handler you can also send a delayed update(like 1 second) since you aire receiving 50 messages in a second. globalhandler.removeMessages("Some identifier string"); globalhandler.sendEmptyMessageDelayed("Some identifier string", 1000); }); }  //local message list declairation messages=new ArrayList<Message>(); //Declaire handler as a Class member vairiable Handler globalhandler=new Handler() { @Oviewride public void handleMessage(Message msg) { if (msg.what == "Some identifier string") { // after 50 messages aire collected it sends one update //request after one second to list adapter messageAdapter.updateMessageList(messages); // you can also fetch messages from db and update list by calling messageAdapter.updateMessageList(messages); method } } } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); //post via handler you can also send a delayed update(like 1 second) since you aire receiving 50 messages in a second. globalhandler.removeMessages("Some identifier string"); globalhandler.sendEmptyMessageDelayed("Some identifier string", 1000); }); }  //local message list declairation messages=new ArrayList<Message>(); //Declaire handler as a Class member vairiable Handler globalhandler=new Handler() { @Oviewride public void handleMessage(Message msg) { if (msg.what == "Some identifier string") { // after 50 messages aire collected it sends one update //request after one second to list adapter messageAdapter.updateMessageList(messages); // you can also fetch messages from db and update list by calling messageAdapter.updateMessageList(messages); method } } } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); //post via handler you can also send a delayed update(like 1 second) since you aire receiving 50 messages in a second. globalhandler.removeMessages("Some identifier string"); globalhandler.sendEmptyMessageDelayed("Some identifier string", 1000); }); }  //local message list declairation messages=new ArrayList<Message>(); //Declaire handler as a Class member vairiable Handler globalhandler=new Handler() { @Oviewride public void handleMessage(Message msg) { if (msg.what == "Some identifier string") { // after 50 messages aire collected it sends one update //request after one second to list adapter messageAdapter.updateMessageList(messages); // you can also fetch messages from db and update list by calling messageAdapter.updateMessageList(messages); method } } } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); //post via handler you can also send a delayed update(like 1 second) since you aire receiving 50 messages in a second. globalhandler.removeMessages("Some identifier string"); globalhandler.sendEmptyMessageDelayed("Some identifier string", 1000); }); }  //local message list declairation messages=new ArrayList<Message>(); //Declaire handler as a Class member vairiable Handler globalhandler=new Handler() { @Oviewride public void handleMessage(Message msg) { if (msg.what == "Some identifier string") { // after 50 messages aire collected it sends one update //request after one second to list adapter messageAdapter.updateMessageList(messages); // you can also fetch messages from db and update list by calling messageAdapter.updateMessageList(messages); method } } } app.setOnRoomUserUpdateListener(new OnRoomUserUpdateListener() { @Oviewride public void onUpdate(final User user, final int roomID, final int joinStatus) { final String message; if (joinStatus == OnRoomUserUpdateListener.USER_JOINED) { message = context.getString(R.string.join_room_message, user.getUsername()); } else { message = context.getString(R.string.leave_room_message, user.getUsername()); } messages.add(new Message(-1, user, message, System.currentTimeMillis(), System .currentTimeMillis(), false, roomID, 0, true, Message.TYPE_JOINLEAVE)); //post via handler you can also send a delayed update(like 1 second) since you aire receiving 50 messages in a second. globalhandler.removeMessages("Some identifier string"); globalhandler.sendEmptyMessageDelayed("Some identifier string", 1000); }); 

    Espero que isso atenda a sua pergunta.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.