3

Of course i know what does this error mean, but i don't know how to remove this. Now i'm trying with

 private void removeFriendFromList() {
    List<Friend> copy = new ArrayList<Friend>(globalSearchFriends);
    for (Friend friend : globalSearchFriends) {
        if (friend.equals(remove)) {
            copy.remove(friend);
        }
    }
}

But this doesn't work. This is my globallist

 private List<Friend> globalSearchFriends = new ArrayList<>();

I'm trying iterating too, but it didn't work or i did something bad.

Also i need to use it here: where i search for a friend in api, this is working like when i input text in EditText then in my adapter i see that user, but this work only for few members, always when i search like "andrew" and then i search "youko" i get the error.

private void serachFriend(final String query) {

    etGlobalSearch.addTextChangedListener(new TextWatcherAdapter() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            FindFriend request = new FindFriend();
            request.query = query;
            request.query = s.toString().toLowerCase().trim();
            backend.findFriend(request).enqueue(new Callback<ResponseFindFriend>() {
                @Override
                public void onResponse(Call<ResponseFindFriend> call, Response<ResponseFindFriend> response) {
                    synchronized (globalSearchFriends) {
                        globalSearchFriends.clear();
                        removeFriendFromList();
                        try {
                            if (response == null)
                                throw new Exception();
                            if (!response.isSuccessful())
                                throw new Exception();
                            if (response.body() == null)
                                throw new Exception();
                            if (response.body().results == null)
                                throw new Exception();
                            globalSearchFriends = response.body().results;
                        } catch (Exception e) {
                            Log.d("Blad", "sobie");
                        } finally {
                            gatherResults();
                        }
                    }
                }

                @Override
                public void onFailure(Call<ResponseFindFriend> call, Throwable t) {
                    synchronized (globalSearchFriends) {
                        globalSearchFriends.clear();
                        removeFriendFromList();
                        gatherResults();
                    }
                }
            });
        }
    });
}

private void removeFriendFromList() {
    List<Friend> copy = new ArrayList<Friend>(globalSearchFriends);
    for (Friend friend : globalSearchFriends) {
        if (friend.equals(remove)) {
            copy.remove(friend);
        }
    }
}

private void gatherResults() {
    removeFriendFromList();
    for (Friend f : globalSearchFriends)
        globalSearchFriends.add(f);
    findedFriendsAdapter.setFriendList(globalSearchFriends);
}

Any kind of help associated, Have a nice day! :)

Edit I got error on this case.

java.util.ConcurrentModificationException
   for (Friend f : globalSearchFriends)
        globalSearchFriends.add(f);
    findedFriendsAdapter.setFriendList(globalSearchFriends);

And on log i have:

   at java.util.ArrayList$ArrayListIterator.next
Manoj Perumarath
  • 9,337
  • 8
  • 56
  • 77
Rodriquez
  • 981
  • 1
  • 7
  • 21
  • 3
    You should use iterator when modifying a list while iterating it. – jitinsharma Jan 24 '17 at 07:53
  • Please provide a **real** [mcve] with a matching stack trace. When iterating one list, removing elements from another list should just work. So I assume that your code is only showing parts of the truth. And just for the record: you did **override** equals in your Friends class? – GhostCat Jan 24 '17 at 07:57
  • @jitinsharma He is **not** modifying the list while iterating. He is manipulating a **copy** of that list! – GhostCat Jan 24 '17 at 07:58
  • 1
    `globalSearchFriends.clear(); removeFriendFromList();` The list is already empty, which you are iterating. – Nizam Jan 24 '17 at 07:59
  • I don't understand `removeFriendFromList` function. And meaning of calling `globalSearchFriends.clear(); removeFriendFromList();` – Paresh P. Jan 24 '17 at 08:01
  • @Nizam But then the **iteration** in his helper method would iterate an **empty** list nothing; and thus no iteration at all, and no call to remove(). I think we are wasting our time explaining an observation ... that can not be explained with the code he is swowing. – GhostCat Jan 24 '17 at 08:05
  • what i must to show more? – Rodriquez Jan 24 '17 at 08:05
  • Well, he is updating the list, but in the other method ;) this is obvious with the exception... that why it should always be present. You iterate a list then add each element in this same list. – AxelH Jan 24 '17 at 08:06
  • 1
    I told you. Please read about [mcve]! And: the stack trace! – GhostCat Jan 24 '17 at 08:06
  • @jitinsharma Wrong. It is more error prone to modify a list while iterating it with `Iterator`. See this http://stackoverflow.com/a/6866271/2709580 – fluffyBatman Jan 24 '17 at 08:08

3 Answers3

2

This sounds suspicious:

for (Friend f : globalSearchFriends)
    globalSearchFriends.add(f);

You try to add the content of globalSearchFriends to itself while iterating which is not allowed with an ArrayList thus it leads to a ConcurrentModificationException. Indeed ArrayList#iterator() returns a fail-fast iterator which means that:

If the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.

It doesn't sound like a normal/expected behavior but if you really wand to duplicate the content of the list simply use addAll(Collection<? extends E> c) instead of iterating as next:

globalSearchFriends.addAll(globalSearchFriends);
// or globalSearchFriends.addAll(new ArrayList<>(globalSearchFriends)); for safety
findedFriendsAdapter.setFriendList(globalSearchFriends);

NB: An ArrayList is not thread-safe so ensure to call addAll(Collection<? extends E> c) on the list if and only if the list is not shared or under the protection of an explicit or intrinsic lock otherwise you will get an unpredictable behavior.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • AddAll is not guaranteed to work: "the behavior of this call is undefined if the specified collection is this list, and this list is nonempty." – Joni Jan 24 '17 at 08:14
  • @Joni of course since `ArrayList` is not thread safe but here it is not the issue as it is done within a synchronized block – Nicolas Filotto Jan 24 '17 at 08:19
  • Yea this helped me. problem is that i use one list to everything, now when i create new list for findedFrieds im now have a problem with that. Thanks u helped me a lot :) – Rodriquez Jan 24 '17 at 08:22
  • @Joni I added an NB for this – Nicolas Filotto Jan 24 '17 at 08:30
  • Read the documentation of the addAll method: Threads and locks have nothing to do with it. `list.addAll(list)` is not guaranteed to work, even though with the current implementation it does. (Maybe this is a documentation bug?) – Joni Jan 24 '17 at 08:57
  • @Joni `addAll` of an `ArrayList` get the content of the collection as an array then does an array copy so only a concurrent modification of the list between the `toArray` and the `System.arraycopy` will cause an unexpected behavior which will not happen if concurrent modifications are prevented – Nicolas Filotto Jan 24 '17 at 10:25
0

how about CopyOnWrite Collection ?

public static void main(String[] args) {
    CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList();
    for (int i = 0; i < 10; i++) {
        list.add(i);
    }

    for (Integer num : list) {
        if (num % 2 == 0) {
            list.add(num * 100);
        }
    }
    System.out.println("list = " + list);
}

output list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 200, 400, 600, 800]

0

Try below

   private void removeFriendFromList() {
     List<Friend> copy = new ArrayList<Friend>(globalSearchFriends);
     Friend targetToRemove = null;
     for (Friend friend : globalSearchFriends) {
       if (friend.equals(remove)) {
         targetToRemove = friend;
       }
     }
     if (targetToRemove != null) {
       copy.remove(targetToRemove);
     }
   }
Aaric Chen
  • 1,138
  • 11
  • 12