0

I'm trying to add new items to a listview throug the addAll method and I can do it on the latest version of android but when I try in older versions it crashes.

Can anyone help me understand why and how to fix it.

Function where i get the error

public void appendMessages(List<Message> moreMessages){
        this.messages.addAll(0,moreMessages);
    }

I need to append them on the top of the list.

Error

09-19 13:12:59.437 12909-12909/com.example.rjrod.legendchat E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.rjrod.legendchat, PID: 12909
    java.util.ConcurrentModificationException
        at java.util.AbstractList$SubAbstractList.size(AbstractList.java:360)
        at java.util.AbstractList$SubAbstractList.addAll(AbstractList.java:265)
        at com.example.rjrod.legendchat.adapter.MensagemAdapter.appendMessages(MensagemAdapter.java:136)
        at com.example.rjrod.legendchat.MainActivity$2.onScroll(MainActivity.java:169)
        at android.widget.AbsListView.invokeOnItemScrollListener(AbsListView.java:1461)
        at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4987)
        at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3398)
        at android.widget.AbsListView.onTouchMove(AbsListView.java:3774)
        at android.widget.AbsListView.onTouchEvent(AbsListView.java:3612)
...

Where i call it

listMensages.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                Log.d(TAG, "onScroll: " + view.getFirstVisiblePosition() + " " + listMensages.getCount() +" " + (19*(k)-visibleItemCount) +" " + k+" " +numberLists);


                if(view.getFirstVisiblePosition() == 0 && listMensages.getCount()>=19*(k)-visibleItemCount && k<numberLists && k>=1 && k!=z){

                    Log.d(TAG, "ENTREI: " + z + " " + k);


                        adapter.appendMessages(messagesList.subList(messagesList.size()-20*(k+1),messagesList.size()-21-((k-1)*20)));
                        adapter.notifyDataSetChanged();
                        listMensages.smoothScrollToPosition(19);
                        z=k;
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            k++;
                        }
                    }, 100);


                        //loaded=true;
                    }
                    if(view.getFirstVisiblePosition() == 0 && listMensages.getCount()>=19-visibleItemCount && k==numberLists){
                        Log.d(TAG, "ENTREI 2: ");

                        adapter.appendMessages(messagesList.subList(messagesList.indexOf(messagesList.get(0)),messagesList.size()-21-((k-1)*20)));
                        adapter.notifyDataSetChanged();
                        listMensages.smoothScrollToPosition(19);
                        k++;
                    }
                    if(k==0){
                        k=1;
                    }



            }
        });

If anything else is needed just tell me and I will add it. (I need this to work from at least sdk 21)

Thanks

Adapter

public class MensagemAdapter extends ArrayAdapter<Message> {

    private Context context;
    private List<Message> messages;
    private List<Users> users;
    private static final String TAG = "MensagemAdapter";


    public MensagemAdapter(@NonNull Context context, @NonNull List<Message> objects, @NonNull List<Users> users) {
        super(context, 0, objects);
        this.context=context;
        this.messages = objects;
        this.users = users;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        View view = null;
        //Log.d(TAG, "getView: " + position);


            if (messages != null) {

                LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
                Message message = messages.get(position);
                //Log.d("Num", "getView: " + message.getUserId() + " " + message.getId());
                if (message.getUserId() == 1) {
                    assert inflater != null;
                    view = inflater.inflate(R.layout.right_no_attach, parent, false);
                    TextView textoMensagem = view.findViewById(R.id.tv_mensage);
                    textoMensagem.setText(message.getContent());
                    if (message.getAttachments() != null) {

                        for (int i = 0; i < message.getAttachments().size(); i++) {
                            //view = inflater.inflate(R.layout.right_attach,parent,false);
                            if (i == 0) {
                                ImageView attach = view.findViewById(R.id.imageView1);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);

                            } else if (i == 1) {
                                ImageView attach = view.findViewById(R.id.imageView2);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);
                            } else if (i == 2) {
                                ImageView attach = view.findViewById(R.id.imageView3);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);
                            } else {
                                ImageView attach = view.findViewById(R.id.imageView3);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);
                            }

                        }
                    }

                } else {
                    assert inflater != null;
                    view = inflater.inflate(R.layout.left_no_attach, parent, false);
                    TextView nomeMensagem = view.findViewById(R.id.nomeId);
                    nomeMensagem.setText(users.get(message.getUserId() - 1).getName());
                    ImageView avatar = view.findViewById(R.id.avatarIm);
                    Picasso.get().load(users.get(message.getUserId() - 1).getAvatarId()).transform(new CircleTransform()).into(avatar);
                    TextView textoMensagem = view.findViewById(R.id.tv_mensage);
                    textoMensagem.setText(message.getContent());
                    if (message.getAttachments() != null) {

                        for (int i = 0; i < message.getAttachments().size(); i++) {
                            //view = inflater.inflate(R.layout.right_attach,parent,false);
                            if (i == 0) {
                                ImageView attach = view.findViewById(R.id.imageViewA);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);

                            } else if (i == 1) {
                                ImageView attach = view.findViewById(R.id.imageViewB);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);
                            } else if (i == 2) {
                                ImageView attach = view.findViewById(R.id.imageViewC);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);
                            } else {
                                ImageView attach = view.findViewById(R.id.imageViewD);
                                attach.setVisibility(View.VISIBLE);
                                Picasso.get().load(message.getAttachments().get(i).getThumbnailUrl()).into(attach);
                            }

                        }
                    }

                }


                if (message.getAttachments() == null) {
                    TextView textoMensagem = view.findViewById(R.id.tv_mensage);

                    textoMensagem.setText(message.getContent());
                }



        }
        return view;
        }


    public void appendMessages(List<Message> moreMessages){
        Log.d(TAG, "appendMessages: " + this.messages + " " + moreMessages);
        this.messages.addAll(moreMessages);

    }


    }
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • 2
    Possible duplicate of [ConcurrentModificationException thrown by sublist](https://stackoverflow.com/questions/8817608/concurrentmodificationexception-thrown-by-sublist) – Anis BEN NSIR Sep 19 '18 at 13:42
  • 2
    A ConcurrentModificationException has nothing to do with an android version. Your list gets modified / processed somewhere else. – kAliert Sep 19 '18 at 13:44
  • @kAliert how can I check if that's the problem and where and how to fix it? – Ricardo Rodrigues Sep 19 '18 at 13:48
  • Without knowing all of your code, my guess is that you are iterating over the list somewhere else. At the same time the iteration happens, you modifie your list with the `appendMessages` method. Just debug your app and see where the list from the adapter gets used. – kAliert Sep 19 '18 at 13:57
  • The code above is the only place i call appendMessages from. – Ricardo Rodrigues Sep 19 '18 at 13:59
  • @kAliert and as you can see in the code I do a Log every time I enter that function . And I only get the log 1 time. – Ricardo Rodrigues Sep 19 '18 at 14:10
  • The problem is not that the method gets called only once. The items you want to add are using a list in the adapter class, which causes the error (`this.messages.addAll(0,moreMessages);`. Please check the usage of the list in your adapter class. – kAliert Sep 19 '18 at 14:15
  • @kAliert added the full code of the adapter – Ricardo Rodrigues Sep 19 '18 at 14:41

2 Answers2

0

To fix tour issue just change the adapter constructor.

public MensagemAdapter(@NonNull Context context, @NonNull List<Message> objects, @NonNull List<Users> users) {
        super(context, 0,  new ArrayList<>(objects));
        this.context=context;
        this.messages =   new ArrayList<>(objects);
        this.users = users;
    }
Anis BEN NSIR
  • 2,555
  • 20
  • 29
0

The problem is you're trying to modify the list while the list is already being modified somewhere else, so you get ConcurrentModificationException.

Try to restrict your list modifications to a single thread for example UI. From your posted code I assume the concurrency occurs in onScoll method which gets called repetitively while your list modification is not finished yet. Here is a simple example of moving your adapter.appendMessages() function to the UI thread queue:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        adapter.appendMessages(messagesList.subList(messagesList.indexOf(messagesList.get(0)),messagesList.size()-21-((k-1)*20)));
        adapter.notifyDataSetChanged();
        listMensages.smoothScrollToPosition(19);
        ...
    }
});
Sdghasemi
  • 5,370
  • 1
  • 34
  • 42