0

I'm having a real troubling issue here, I'm encountering a ConcurrentModificationException in the ArrayAdapter.add(Object o) method. Actually the stacktrace points to to the list.size() method in the ArrayAdapter. But it's incredibly unusual since I don't even iterate the list. Here's the code snippet that crashes the code:

private void addCharacterToPager(Character savedChar) {
        RelativeLayout lastGrid = pagerAdapter.retrieveViews().get(
                pagerAdapter.getCount() - 1);
        // get gridview
        GridView lastGridView = (GridView) lastGrid.getChildAt(lastGrid
                .getChildCount() - 1);
        CharacterGridAdapter adapter = (CharacterGridAdapter) lastGridView
                .getAdapter();


        adapter.add(savedChar);
        adapter.notifyDataSetChanged();
        pagerAdapter.retrieveViews().set(pagerAdapter.getCount(), lastGrid);
        pagerAdapter.notifyDataSetChanged();

    }

This is my custom ArrayAdapter:

public class CharacterGridAdapter extends ArrayAdapter<Character> {

private Context context;
private List<Character> objects;
private int resource;

public CharacterGridAdapter(Context context, int resource,
        List<Character> listChar) {
    super(context, resource, listChar);
    this.context = context;
    this.resource = resource;
    this.objects = listChar;
}

public void updateCollection(List<Character> listChar) {
    this.objects = listChar;
}

public List<Character> retrieveCollection() {
    return this.objects;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View rowView = convertView;
    ImageView charImg = null;
    if (rowView == null) {
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        rowView = inflater.inflate(R.layout.charactergrid_cell, null);
        charImg = (ImageView) rowView
                .findViewById(R.id.characterImage_cell);
    } else {
        charImg = (ImageView) convertView
                .findViewById(R.id.characterImage_cell);
    }

    Character currentChar = objects.get(position);

    if (currentChar.getName().equals("add")
            && currentChar.getGame().equals("add")) {
        //set charimg to add icon
        charImg.setImageResource(R.drawable.add);
    } else {
        if(currentChar.getCharacterImage() != null) {
            //set charimg to url
            Picasso.with(context).load(currentChar.getCharacterImage().getUrl()).into(charImg);
        } else {
            //set charimg to default
        }
    }

    return rowView;
}

}

This is the stacktrace:

01-29 12:58:12.666: E/AndroidRuntime(18891):at java.util.ConcurrentModificationException
01-29 12:58:12.666: E/AndroidRuntime(18891):at java.util.AbstractList$SubAbstractList.size(AbstractList.java:360)
01-29 12:58:12.666: E/AndroidRuntime(18891):at java.util.AbstractList.add(AbstractList.java:425)
01-29 12:58:12.666: E/AndroidRuntime(18891):at android.widget.ArrayAdapter.add(ArrayAdapter.java:179)
01-29 12:58:12.666: E/AndroidRuntime(18891):at com.xx.playpalproject.ProfileActivity$SaveCharacter.addCharacterToPager(ProfileActivity.java:648)

I really don't get the issue, all I'm trying to do is add an item to the adapter..

Update

I solved the initial issue, I was adding an item to the collection that I set the adapter to before executing the addCharacterToPager method. BUT this didn't solve it at all really. Now I get the exact same error but when trying to modify the pagerAdapter collection and notifying that it's data has changed. So the original problem is still there but it moved it has moved to another adapter..

Update 2

Instead of trying to add an item, I tried to rebuilding the entire ViewPager and to my surprise it ALSO gave me a ConcurrentModificationException. This time it is thrown in the getCount() method of an ArrayAdapter, but I don't know if this is actually my custom adapter. Here's the stacktrace:

01-29 14:26:56.036: E/AndroidRuntime(23898): FATAL EXCEPTION: main
01-29 14:26:56.036: E/AndroidRuntime(23898): java.util.ConcurrentModificationException
01-29 14:26:56.036: E/AndroidRuntime(23898):    at java.util.AbstractList$SubAbstractList.size(AbstractList.java:360)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.widget.ArrayAdapter.getCount(ArrayAdapter.java:330)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.widget.AbsListView.onAttachedToWindow(AbsListView.java:2642)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.View.dispatchAttachedToWindow(View.java:11983)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2495)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2502)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.ViewGroup.addViewInner(ViewGroup.java:3469)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.ViewGroup.addView(ViewGroup.java:3301)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.support.v4.view.ViewPager.addView(ViewPager.java:1304)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.ViewGroup.addView(ViewGroup.java:3246)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.view.ViewGroup.addView(ViewGroup.java:3222)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at com.timkranen.adapters.CustomPagerAdapter.instantiateItem(CustomPagerAdapter.java:22)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:832)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.support.v4.view.ViewPager.populate(ViewPager.java:982)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:442)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at com.xx.playpalproject.ProfileActivity.setupCharacterGrid(ProfileActivity.java:175)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at com.xx.playpalproject.ProfileActivity.access$8(ProfileActivity.java:166)
01-29 14:26:56.036: E/AndroidRuntime(23898):    at com.xx.playpalproject.ProfileActivity$SaveCharacter.done(ProfileActivity.java:638)

The setupCharacterGrid() method:

private void setupCharacterGrid() {
    charPager.setAdapter(null);
    List<List<Character>> dividedLists = Lists.partition(currentCharacters,
            9);
    if (isOwner) {
        dividedLists.get(0).add(0, new Character("add", "add"));
    }
    fillGrids(dividedLists);
    pagerAdapter = new CustomPagerAdapter(characterGrids);
    charPager.setAdapter(pagerAdapter);
    charPager.setPageTransformer(true, new ZoomPagerTransformer());
    charPager.setCurrentItem(0);
}

And the fillGrids() method:

private void fillGrids(List<List<Character>> divList) {
    for (List<Character> list : divList) {
        RelativeLayout rLayout = new RelativeLayout(this);
        GridView gridView = new GridView(this);
        gridView.setNumColumns(3);
        gridView.setVerticalSpacing(70);
        CharacterGridAdapter aa = new CharacterGridAdapter(this,
                R.layout.charactergrid_cell, list);
        gridView.setAdapter(aa);
        gridView.setLayoutParams(genLayoutParams());
        gridView.setOnItemClickListener(new GridClick());
        rLayout.addView(gridView);
        characterGrids.add(rLayout);
    }
}

The CustomPagerAdapter:

public class CustomPagerAdapter extends PagerAdapter {

public List<RelativeLayout> gridViews;

public CustomPagerAdapter(List<RelativeLayout> gridViews) {
    this.gridViews = gridViews;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    RelativeLayout gridView = gridViews.get(position);
    container.addView(gridView);
    return gridView;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView(gridViews.get(position));
}

@Override
public int getCount() {
    return gridViews.size();
}

@Override
public boolean isViewFromObject(View view, Object o) {
    return view == o;
}

public List<RelativeLayout> retrieveViews() {
    return gridViews;
}

public void updateCollection(List<RelativeLayout> gridViews) {
    this.gridViews = gridViews;
}

}

Tim Kranen
  • 4,202
  • 4
  • 26
  • 49
  • Do you have any threads working with that ArrayList? – nKn Jan 29 '14 at 12:03
  • No, that's also the weird thing this doesn't use any threads whatsoever. – Tim Kranen Jan 29 '14 at 12:05
  • 1
    ConcurrenttModificationException is not particularly applicable in multi-threaded applications. That exception can even happen in single threaded applications and it all depends on how the collection underlying the iterator is being manipulated – sadhu Jan 29 '14 at 12:07
  • Yeah, but I'm not iterating over the collection myself. I'm just trying to add to the collection using a standard method. – Tim Kranen Jan 29 '14 at 12:09
  • @sadhu I know, I was just trying because in the provided code I don't see any issue at first sight. – nKn Jan 29 '14 at 12:17
  • @NKN I've updated my original post with more info, hopefully this might help you. – Tim Kranen Jan 29 '14 at 12:34
  • Could you update the stacktrace with the new error, and point the line numbers to the code you've pasted? – nKn Jan 29 '14 at 13:22
  • What's your current 175th line of your ProfileActivity.java file? – nKn Jan 29 '14 at 13:38
  • @NKN That's where I set the Adapter to the Viewpager: charPager.setAdapter(pagerAdapter); – Tim Kranen Jan 29 '14 at 13:40
  • The exception origin starts in the line 22 of your CustomPagerAdapter implementation. You should include it in the question and point which is the 22th line. – nKn Jan 29 '14 at 13:51
  • @NKN Posted, line 22 is container.addView(gridView);, I still don't see a problem with any of this.. It's extremely frustrating. – Tim Kranen Jan 29 '14 at 13:54
  • Try replacing `container.addView(gridView);` by `synchronized { container.addView(gridView); }` in the 22th line of your CustomPagerAdapter. – nKn Jan 29 '14 at 14:40
  • @NKN As in put it in a synchronized method? – Tim Kranen Jan 29 '14 at 14:42
  • Yes, just replace your line by the mine - This could solve the issue, but I actually don't know **why** is it happening. I'm trying to find out though. – nKn Jan 29 '14 at 14:44
  • @NKN Nope.. Didn't work :(, I appreciate your help though! I've been searching for hours and can't find anything.. – Tim Kranen Jan 29 '14 at 14:46

1 Answers1

0

I think the mistake is in your instantiatItem() method. Whatever implementations I've seen, this method seems to be intended to create a new object, not to reference an existing one. You'll need to use new of inflater.inflate and add this view to the container viewgroups.

The way you're using it seems that getCount() expects a different number of elements than it's provided, this would have sense if you're just referencing an object instead of creating it like I wrote above, and concludes that it's being modified by several methods. Try creating of inflating a new instance and it should work.

nKn
  • 13,691
  • 9
  • 45
  • 62
  • But if I have to create the object in the instantiateItem() I can never bind a collection to the Adapter? How can I instantiate multiple dynamic items then? – Tim Kranen Jan 29 '14 at 15:12