2

I am using a ExpandableRecyclerView by Big Nerd Ranch like the one in this example. The problem is whenever I try to add another sub item to my RecyclerView dynamically the space of this new item occupies the space of an item that was already there, kinda like deleting this item from the screen. I don't know how to explain it better so I've attached the following screenshots:

enter image description here

The above picture shows the list before addinga new sub item. When I click in the add button, I need to collapse the child view and then expand it again so it appears like bellow:

enter image description here

The New Item view pushes down the other child views, occupying the space that once was for the Item 2. And if I try to add a new child item to the last parent item it gives this error:

E/AndroidRuntime: FATAL EXCEPTION: main
                                                Process: com.dietando.gabriel.dietando, PID: 4037
                                                                         java.lang.IndexOutOfBoundsException: Invalid index 8, size is 8
                                                                             at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
                                                                             at java.util.ArrayList.remove(ArrayList.java:403)
                                                                             at com.bignerdranch.expandablerecyclerview.Adapter.ExpandableRecyclerAdapter.expandParent(ExpandableRecyclerAdapter.java:319)
                                                                             at com.bignerdranch.expandablerecyclerview.Adapter.ExpandableRecyclerAdapter.onParentItemClickListener(ExpandableRecyclerAdapter.java:252)
                                                                             at com.bignerdranch.expandablerecyclerview.ViewHolder.ParentViewHolder.onClick(ParentViewHolder.java:200)
                                                                             at android.view.View.performClick(View.java:5198)
                                                                             at android.view.View$PerformClick.run(View.java:21147)
                                                                             at android.os.Handler.handleCallback(Handler.java:739)
                                                                             at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                             at android.os.Looper.loop(Looper.java:148)
                                                                             at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                             at java.lang.reflect.Method.invoke(Native Method)
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

When I add the new sub item, I add a new item to my array list and then call the method notifyDataSetChanged().

Here is my adapter code:

    public class MealExpandableAdapter extends ExpandableRecyclerAdapter<MealParentViewHolder, MealChildViewHolder>
{
    private Context context;
    private List<ParentObject> refeicoes;
    private boolean[] checkedState;
    private LayoutInflater mInflater;
    private MealExpandableAdapter.MealChildViewHolderListener onChildCheckChangedListener;

    public interface MealChildViewHolderListener
    {
        public void onCheckChange(int mealNumber, Food food, boolean selected);
    }

    public MealExpandableAdapter(Context context, List<ParentObject> refeicoes)
    {
        super(context, refeicoes);

        this.context = context;
        this.refeicoes = refeicoes;
        mInflater = LayoutInflater.from(context);

        checkedState = new boolean[refeicoes.size()];

        for(int i = 0; i < checkedState.length; ++i)
            checkedState[i] = false;


    }

    protected void setOnChilCheckedChangedListener(MealExpandableAdapter.MealChildViewHolderListener onChildCheckChangedListener)
    {
        this.onChildCheckChangedListener = onChildCheckChangedListener;
    }

    @Override
    public MealParentViewHolder onCreateParentViewHolder(ViewGroup viewGroup)
    {
        View view = mInflater.inflate(R.layout.adapter_refeicao, viewGroup, false);
        return new MealParentViewHolder(view);
    }

    @Override
    public MealChildViewHolder onCreateChildViewHolder(ViewGroup viewGroup)
    {
        View view = mInflater.inflate(R.layout.adapter_refeicao_child, viewGroup, false);
        return new MealChildViewHolder(view);
    }

    @Override
    public void onBindParentViewHolder(MealParentViewHolder mealParentViewHolder, final int mealNumber, Object parentObject)
    {
        final Meal meal = (Meal) parentObject;
        mealParentViewHolder.mMealParentTextView.setText(meal.getNome());
        mealParentViewHolder.mMealParentImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("Teste", "img btn click");
                meal.addFood(0, new Food("New item", 30, 30, 30));
                //notify();
                //notifyItemInserted(mealNumber);
                notifyDataSetChanged();
                notifyItemChanged(mealNumber);


            }
        });

    }

    @Override
    public void onBindChildViewHolder(final MealChildViewHolder mealChildViewHolder, final int mealNumber, Object childObject)
    {
        //final Meal meal = (Meal) refeicoes.get(mealNumber);
        final Food food = (Food) childObject;
        mealChildViewHolder.mMealChildTextView.setText(food.getName());
        mealChildViewHolder.mMealChildCheckBox.setChecked(food.isChecked());
        mealChildViewHolder.mMealChildCheckBox.setChecked(food.isChecked());
        mealChildViewHolder.mMealChildCheckBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (((CheckBox) v).isChecked()) {
                    Log.i("Teste", "checked");
                    food.checkFood();
                    onChildCheckChangedListener.onCheckChange(mealNumber, food, true);
                } else {
                    Log.i("Teste", "unchecked");
                    food.checkFood();
                    onChildCheckChangedListener.onCheckChange(mealNumber, food, false);
                }
            }

        });
    }

Here is my ParentViewHolder:

    public class MealParentViewHolder extends ParentViewHolder
{
    public TextView mMealParentTextView;
    public ImageButton mMealParentImageButton;
    public CheckBox mMealParentCheckBox;

    public MealParentViewHolder(View itemView)
    {
        super(itemView);

        mMealParentTextView = (TextView) itemView.findViewById(R.id.tTitle);
        mMealParentImageButton = (ImageButton) itemView.findViewById(R.id.imgBtnParent);
        mMealParentCheckBox = (CheckBox) itemView.findViewById(R.id.checkBox);
    }
}

And here is my ChildViewHolder

    public class MealChildViewHolder extends ChildViewHolder
{
    public TextView mMealChildTextView;
    public CheckBox mMealChildCheckBox;



    public MealChildViewHolder(View itemView)
    {
        super(itemView);


        mMealChildTextView = (TextView) itemView.findViewById(R.id.txtFragMeal);
        mMealChildCheckBox = (CheckBox) itemView.findViewById(R.id.checkBoxFragMeal);
        mMealChildCheckBox.setChecked(false);
        mMealChildCheckBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (((CheckBox) v).isChecked()) {
                    Log.i("Teste", "checked");

                } else {


                }
            }
        });
    }
}

That's how I'm initalizing the ViewHolder in my Fragment:

RecyclerView recyclerView = (RecyclerView) getView().findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        meals = user.getDiet().getMeals();

        MealExpandableAdapter mMealExpandableAdapter = new MealExpandableAdapter(getActivity(), meals);
        mMealExpandableAdapter.setOnChilCheckedChangedListener(onChildCheckChangedListener());
        // mCrimeExpandableAdapter.setCustomParentAnimationViewId(R.id.parent_list_item_expand_arrow);
        mMealExpandableAdapter.setParentClickableViewAnimationDefaultDuration();
        mMealExpandableAdapter.setParentAndIconExpandOnClick(true);


        recyclerView.setAdapter(mMealExpandableAdapter);

I think the problem is with the adapter but I have no idea what's wrong, I''l appreciate any help.

Gabriel Schneider
  • 605
  • 2
  • 6
  • 12

1 Answers1

0

I bet the problem is around this line:

checkedState = new boolean[refeicoes.size()];

Arrays are 0 based.

A list that contains 5 elements will create an array with 6 entries. So when you try to iterate the array over the length you get the ArrayIndexOutOfBoundsExceptionbecause the array contains one less entry than you are expecting.

Emmanuel
  • 13,083
  • 4
  • 39
  • 53