Search code examples
javaandroidcustom-adapter

"Variable is accessed from within inner class, needs to be declared final" error in custom adapter


I'm attempting to implement a multiple choice ListView with checkboxes, and I've defined a custom adapter class, and it's as follows:

package com.ameer.easycooking;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class CategoryAdapter extends ArrayAdapter<String> {

    private List<String> categoryList;
    private Context context;
    private List<String> selected = new ArrayList<>();

    public CategoryAdapter(List<String> categoryList, Context context) {
        super(context, R.layout.category_list_item, categoryList);
        this.categoryList = categoryList;
        this.context = context;
    }

    public static class CategoryHolder {
        private CheckBox checkBox;
        private TextView categoryName;

        public CategoryHolder(CheckBox checkBox, TextView categoryName) {
            this.checkBox = checkBox;
            this.categoryName = categoryName;
        }

        public CheckBox getCheckBox() {
            return checkBox;
        }

        public void setCheckBox(CheckBox checkBox) {
            this.checkBox = checkBox;
        }

        public TextView getCategoryName() {
            return categoryName;
        }

        public void setCategoryName(TextView categoryName) {
            this.categoryName = categoryName;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;

        CategoryHolder holder = new CategoryHolder((CheckBox) v.findViewById(R.id.checkBox), (TextView) v.findViewById(R.id.name));

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.category_list_item, null);

            holder.getCheckBox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        if (isChecked) {
                            selected.add(holder.getCheckBox().getText().toString());
                        }else{
                            selected.remove(holder.getCheckBox().getText().toString());
                        }
                }
            });
            v.setTag(holder);
        } else {
            holder = (CategoryHolder) v.getTag();
        }

        String category = categoryList.get(position);
        holder.categoryName.setText(category);
        holder.checkBox.setTag(category);

        return v;
    }

    public List<String> getSelected() {
        return selected;
    }
}

I would like to store checked items in the selected List and then retrieve them with the getter at the end of the class, but It's telling me that 'holder' needs to be declared final, and if I do declare it final I can no longer assign a value to it using holder = (CategoryHolder) v.getTag(); So solving one problem is creating another one. :( How can I solve both?

Thanks in advance.


Solution

  • You can get the necessary information from the parameters of the OnCheckedChangeListener: buttonView is the checked element. So all you need to do is the following:

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
           CheckBox checkbox;
           if (buttonView instanceof CheckBox )
           {
               checkbox = (CheckBox)buttonView;
           }
           else return;
    
           if (isChecked) {
                selected.add(checkbox.getText().toString());
           }else{
                selected.remove(checkbox.getText().toString());
           }
    }