创建聊天应用程序时出现 ConcurrentModificationException

Posted

技术标签:

【中文标题】创建聊天应用程序时出现 ConcurrentModificationException【英文标题】:I am getting ConcurrentModificationException while creating a chat application 【发布时间】:2019-06-02 09:02:10 【问题描述】:

在应用程序中显示最近的聊天片段时,我从 firebase 获取我的聊天,并通过聊天对象中的接收者 ID 和发送者 ID 过滤掉聊天以显示最近的聊天。

问题在 ArrayList 中显示 ConcurrentModificationException,看起来由于在数组中搜索 id 的复杂性,我需要一个解决方案来最小化这种聊天过滤的复杂性。

  // private List<String> stringList; Declaration at top 
    stringList = new ArrayList<>();
    firebaseUser = FirebaseAuth.getInstance().getCurrentUser();

    databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Chats/");
    databaseReference.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
            //userModelList.clear();
            for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) 
                MessageModel messageModel = dataSnapshot1.getValue(MessageModel.class);

                if (messageModel.getSender().equals(firebaseUser.getUid()))
                  stringList.add(messageModel.getReceiver());
                
                if (messageModel.getReceiver().equals(firebaseUser.getUid()))
                    stringList.add(messageModel.getSender());
                
            
            readChat();
        
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) 
        
    );

阅读聊天功能

  private void readChat() 

    userModelList = new ArrayList<>();
    databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Users/");

    databaseReference.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
            userModelList.clear();
            for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren())
                UserModel userModel = dataSnapshot1.getValue(UserModel.class);

                for (String id: stringList)
                    if (userModel.getId().equals(id))
                        if (userModelList.size() !=0)
                            for (UserModel userModel1 : userModelList)
                                if (!userModel.getId().equals(userModel1.getId()))
                                    userModelList.add(userModel);
                                    Log.d("DataAdded",userModel.getId());
                                 // If the existing list don't have same value for sender and reciever
                             // end of inner userModel
                         else 
                            userModelList.add(userModel);
                            Log.d("DataAdded",userModel.getId());
                         // end of else
                       // end of userModel id equals string id
                   // end of String is loop
               // end of DataSnapshot loop

            usersAdapter = new UsersAdapter(userModelList);
            recyclerView.setAdapter(usersAdapter);


         // end of onDataChange

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) 
        
    );
// end of readChat()

结果将是最近聊天的 recyclerView,其中包含包含由发送者或接收者相互发送的消息的聊天。

【问题讨论】:

MessageModel 对象包含 3 个值 "message" : "hi", "receiver" : "OiMmgOLTPhdgcizouU9ylHhiXRV2", "sender" : "piXG0LgakVYD3bnlhbYqecCdiOw1" 【参考方案1】:

在下面的sn-p代码中:

for (UserModel userModel1 : userModelList)
   if (!userModel.getId().equals(userModel1.getId()))
        userModelList.add(userModel);
        Log.d("DataAdded",userModel.getId());
     // If the existing list don't have same value for sender and reciever
 //

您在迭代 userModelList 时正在修改 userModelList。这是不允许的,是ConcurrentModificationException 的原因。

简化逻辑的方法很少,最简单的(尽管不是最好的)是将这个foreach循环转换为一个简单的for i循环。

for (int i = 0; i< userModelList.size(); i++) 
    UserModel userModel1 = userModelList.get(i);
    if (!userModel.getId().equals(userModel1.getId()))
       userModelList.add(userModel);
       Log.d("DataAdded",userModel.getId());
     // If the existing list don't have same value for sender and reciever
 //

【讨论】:

感谢,因为我通过为最近的聊天列表创建一个单独的节点来更改从所有聊天中搜索的系统,从而获得了解决方案。【参考方案2】:

基本上为了处理这种复杂性,我现在使用单独的节点来存储聊天列表,因此我不需要阅读聊天来过滤最近的聊天。

以下代码用于每次用户发送消息时创建一个新节点,如果接收者ID不同,它将更新节点。

dbrefChatList = FirebaseDatabase.getInstance().
                getReference("BaatCheet/ChatList/")
                .child(senderuserID)
                .child(receiveruserID);

        dbrefChatList.addListenerForSingleValueEvent(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                if (!dataSnapshot.exists())
                    dbrefChatList.child("id").setValue(receiveruserID);
                
            
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 
            
        );

因此 ChatList 是一个模型类,其中包含一个名为“id”的字符串,该 id 将用于在节点中搜索。

以下代码用于 ChatFragment,它从 firebase 获取 chatList 并将数据设置为回收站视图。

      // private List<ChatList> chatList; Declaration at top
    chatListList = new ArrayList<>();
    firebaseUser = FirebaseAuth.getInstance().getCurrentUser();

    databaseReference = FirebaseDatabase
            .getInstance()
            .getReference("BaatCheet/ChatList")
            .child(firebaseUser.getUid());

    databaseReference.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) 

            chatListList.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren())
                    ChatList chatList = snapshot.getValue(ChatList.class);
                    chatListList.add(chatList);
                
                myChatList();
        
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) 
        
    );

函数myChatList充当问题陈述中的readChat函数。

 private void myChatList() 

    userModelList = new ArrayList<>();
    databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Users/");
    databaseReference.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
            userModelList.clear();
            for (DataSnapshot snapshot : dataSnapshot.getChildren())
                UserModel userModel = snapshot.getValue(UserModel.class);
                for (ChatList chatList : chatListList)
                    if (userModel.getId().equals(chatList.getId()))
                        userModelList.add(userModel);
                    
                
            
            usersAdapter = new UsersAdapter(userModelList);
            recyclerView.setAdapter(usersAdapter);
        
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) 
        
    );


【讨论】:

以上是关于创建聊天应用程序时出现 ConcurrentModificationException的主要内容,如果未能解决你的问题,请参考以下文章

使用 aSmack 为 XMPP 群聊创建 MUC 房间时出现 ClassCastException

创建 MultiUserChat 时出现 NoResponseException

facebook 聊天进入网站时出现内容安全策略错误?

创建 MultiUserChat 房间时出现未授权错误

PHP - 使用 JAXL 登录 Facebook 聊天时出现问题

尝试使用 smack 连接 facebook 聊天时出现此错误