problem of cant add element while iterating. i tried th emethod of creating another arraylist nd store element there and add them all in one time but it didnt work because you nedd the arraymist size to operate right. any help pls.
private void readChats(){
mUsers = new ArrayList<>();
reference = FirebaseDatabase.getInstance().getReference("Users");
reference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
mUsers.clear();
for(DataSnapshot dataSnapshot : snapshot.getChildren()){
User user = dataSnapshot.getValue(User.class);
//display 1 user from chats
for(String id : usersList){
if(user.getId().equals(id)){
if(mUsers.size() != 0){
for(User user1 : mUsers){
if(!user.getId().equals(user1.getId())){
mUsers.add(user);
}
}
}else{
mUsers.add(user);
}
}
}
}
userAdapter = new UserAdapter(getContext(), mUsers, true);
recyclerView.setAdapter(userAdapter);
}
CodePudding user response:
You're doing the following:
- Obtain an
iterator
from some collection object. afor (var foo : collectionObject)
does this. Also, callingcollectionObject.iterator()
does this. - Modify the collection, and not via the iterator. In any way;
.clear()
,.add()
- etc. - Interact with the iterator somehow. When your
for (var foo : collection)
loops, that'll do it. So will callinghasNext()
ornext()
on that iterator.
Then, boom, ConcurrentModificationException will always occur, unless the type of the collection explicitly calls out in its documentation that it deals with such issues differently (for example, CopyOnWriteArrayList
is one such particular implementation that would not, and the reason it would not is spelled out in its javadoc.
You're doing precisely that: you're modifying the list itself as you iterate through it. You can't do that, and there's a good reason.When you call mUsers.add
while you're looping through all the elements in mUsers
, did you intend for that loop to then also loop over this freshly added item? It's likely to lead to lots of endless loops if that's the case. Or was your intent that the for loop should loop through everything as it was when the for loop begins, thus, anything you delete or add during the loop doesn't change what you loop through? Perhaps - but this requires copying the list. If the list is large, that's very pricey.
You see why java doesn't let you do this. It's an intentional design decision.
If you really did intend to edit the list while looping it, there are a few ways to 'fix' things:
Use ListIterator instead, or add things to a second list and once the for loop is done, use .addAll
to add all elements in the temporary list to the main list.
However, that is not your problem here.
Instead, your code is just broken. I think the intent is to only execute mUsers.add(user)
if user
is not already in mUsers
.
That's not what your code does even if you adressed the 'you cannot modify a list while looping through it' aspect of it. Your code would execute mUsers.add(user)
once for every existing user name in the list that isn't identical to user. In other words, if your list is [Jane, Jackie, Jill]
and I tried to add Jackie
to it, your list ends up being [Jane, Jackie, Jill, Jackie, Jackie]
- clearly not what you wanted.
Either simply use a Set
(which silently ignores attempts to add stuff that is already in there), or get rid of the inner for loop. All you need is:
if (!mUsers.contains(user)) mUsers.add(user);
CodePudding user response:
You can't add to mUsers while iterating over it in this async fashion
Use something that is concurrency friendly such as a concurrenthashset, queue, or copy on write array for mUsers