skip to Main Content

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

2

Answers


  1. 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

    Login or Signup to reply.
  2. You’re doing the following:

    1. Obtain an iterator from some collection object. a for (var foo : collectionObject) does this. Also, calling collectionObject.iterator() does this.
    2. Modify the collection, and not via the iterator. In any way; .clear(), .add() – etc.
    3. Interact with the iterator somehow. When your for (var foo : collection) loops, that’ll do it. So will calling hasNext() or next() 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);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search