0

I'm aware that multiple questions have been asked that are similar to my problem but no answer has yet solved my particular problem.

I have a BaseAdapter which prepares a list with checkboxes.

Here is the relevant code of the adapter -

 @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        selectedFolderIds = new ArrayList<>();
        selectedFolderNames = new ArrayList<>();
        selectedFolderParentIds = new ArrayList<>();
        deselectedFolderIds = new ArrayList<>();

        final FolderStructureDataModel folderDetails = (FolderStructureDataModel) getItem(position);

        final ViewHolder holder;
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if(convertView == null) {
            convertView = inflater.inflate(R.layout.folder_structure_list_item_template,
                    parent, false);
            holder = new ViewHolder();
            holder.folderListLayout = (RelativeLayout) convertView.findViewById(R.id.folder_list_layout);
            holder.childFoldersIndicator = (ImageView)
                    convertView.findViewById(R.id.child_folders_indicator);
            holder.selectionCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
            holder.selectionCheckBox.setOnCheckedChangeListener(null);
            holder.selectionCheckBox.setOnClickListener(null);
        }

        /**
         * Attach the listeners to the checkboxes.
         */
        holder.selectionCheckBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                CheckBox cb = (CheckBox) view;
                if (cb.isChecked()) {
                    selectedFolderIds.add(HelperFunctions.EncodeString(folderDetails.ID));
                    selectedFolderNames.add(HelperFunctions.EncodeString(folderDetails.DisplayName));
                    selectedFolderParentIds.add(HelperFunctions.EncodeString(folderDetails.ParentFolderID));

                    SelectedFolderListener selectedFolderListener =
                            (SelectedFolderListener) context;
                    selectedFolderListener.getSelectedFoldersArrayList(selectedFolderIds,
                            selectedFolderNames, selectedFolderParentIds);

                    Log.i("Test : " + folderDetails.DisplayName + " at position " +
                            String.valueOf(position), "Set to " +
                            String.valueOf(checkboxStatus.get(position))
                            + " From onClickListener");
                } else {
                    selectedFolderIds.remove(HelperFunctions.EncodeString(folderDetails.ID));
                    selectedFolderNames.remove(HelperFunctions
                            .EncodeString(folderDetails.DisplayName));
                    selectedFolderParentIds.remove(HelperFunctions
                            .EncodeString(folderDetails.ParentFolderID));
                    deselectedFolderIds.add(HelperFunctions.EncodeString(folderDetails.ID));

                    UnselectedFolderListener unselectedFolderListener =
                            (UnselectedFolderListener) context;
                    unselectedFolderListener.getDeselectedFolderArrayList(deselectedFolderIds);

                    Log.i("Test : " + folderDetails.DisplayName + " at position " +
                            String.valueOf(position), "Set to " +
                            String.valueOf(checkboxStatus.get(position))
                            + " From onClickListener");
                }
            }
        });

        holder.selectionCheckBox.setOnCheckedChangeListener
                (new CompoundButton.OnCheckedChangeListener() {

                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                        if (((buttonView).isChecked()) && isChecked) {
                            checkboxStatus.set(position, true);
                            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                                    String.valueOf(position), "Set to " +
                                    String.valueOf(checkboxStatus.get(position))
                                    + " From onCheckChangedListener");
                        } else {
                            checkboxStatus.set(position, false);
                            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                                    String.valueOf(position), "Set to " +
                                    String.valueOf(checkboxStatus.get(position))
                                    + " From onCheckChangedListener");
                        }
                    }
                });

        //Populate the data
        holder.selectionCheckBox.setText(String.valueOf(folderDetails.DisplayName));

        if(Integer.valueOf(folderDetails.ChildFolderCount) == 0) {
            holder.childFoldersIndicator.setVisibility(View.GONE);
            holder.folderListLayout.setFocusable(true);
            holder.folderListLayout.setClickable(true);
        } else {
            holder.childFoldersIndicator.setVisibility(View.VISIBLE);
            holder.folderListLayout.setFocusable(false);
            holder.folderListLayout.setClickable(false);
        }

        /**
         * Set the checkbox as per the service reply (status in the server)
         */
        if(Boolean.valueOf(folderDetails.IsAlreadySelected)) {
            holder.selectionCheckBox.setChecked(true);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From folderDetails");
        } else {
            holder.selectionCheckBox.setChecked(false);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From folderDetails");
        }

        /**
         * Set the checkbox as per the values maintained in the checkboxStatus ArrayList
         */
        if(checkboxStatus.get(position)) {
            holder.selectionCheckBox.setChecked(true);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From checkBoxStatus");
        } else {
            holder.selectionCheckBox.setChecked(false);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From checkBoxStatus");
        }

        return convertView;
    }

I have an ArrayList checkboxStatus which maintains the status of checkboxes at each position.

The problem I'm facing is that if a checkbox is already checked (according to value of 'folderDetails.IsAlreadySelected'), I uncheck it and I scroll down and then scroll back up, the checkbox gets checked again. The peculiar part is that this does not happen in the opposite case - If the checkbox is unchecked, I check it and scroll down and then scroll back up again; the status remains as checked.

What could possibly be wrong with the Adapter?

krtkush
  • 1,378
  • 4
  • 23
  • 46

1 Answers1

2

To solve you problem do this:

if(convertView == null) {
        convertView = inflater.inflate(R.layout.folder_structure_list_item_template,
                parent, false);
        holder = new ViewHolder();
        holder.folderListLayout = (RelativeLayout) convertView.findViewById(R.id.folder_list_layout);
        holder.childFoldersIndicator = (ImageView)
                convertView.findViewById(R.id.child_folders_indicator);
        holder.selectionCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);
  // Add this line, set tag on your checkbox.
 holder.selectionCheckBox .setTag(holder);
        convertView.setTag(holder);
    }

Now on clicklistner,

 holder.selectionCheckBox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
         // add this line,declare holder_new as an instance of ViewHolder
        holder_new= (ViewHolder) view.getTag();
            // rest is your code what you have already written
    });

Now after onclick, wherever you are accessing selectionCheckBox using holder, change it to holder_new.

holder.selectionCheckBox.setChecked(true); change it to holder_new.selectionCheckBox.setChecked(true);

Harish Vats
  • 662
  • 6
  • 21
  • `holder_new== (ViewHolder) view.getTag();` I'm assuming you meant `holder_new = (ViewHolder) view.getTag();`, right? Plus, where do I declare `holder_view`? – krtkush Sep 04 '15 at 10:47
  • yup.. typing error :P declare it at same place where declaring "holder".. Its upto you, you can declare it at class level also. – Harish Vats Sep 04 '15 at 11:02
  • I have to make it global, otherwise I'll get the `variable accessed from inner class needs to be declared final` error. I tried your implementation with the above changes and the activity is crashing because of a NullPointerException at `holder_new.selectionCheckBox.setChecked(true);` – krtkush Sep 04 '15 at 11:07
  • // add this line,declare holder_new as an instance of ViewHolder holder_new= (ViewHolder) view.getTag(); didn't you initialise holder_new ? – Harish Vats Sep 04 '15 at 11:30
  • I did. I made a global variable `holder_new`, initiated it in adapter constructor with `viewHolder = new ViewHolder();` and then followed what you said above. I still get a NPE. – krtkush Sep 04 '15 at 11:46
  • all you have to do are two steps: 1. In if(convertview==null){ holder.selectionCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox); // Add this line, set tag on your checkbox, holder.selectionCheckBox .setTag(holder); } 2. on clicklistner on checkbox holder.selectionCheckBox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // add this line,declare holder_new as an instance of ViewHolder holder_new= (ViewHolder) view.getTag(); }); – Harish Vats Sep 04 '15 at 11:58
  • show me your complete code of this adapter, not just the getView() – Harish Vats Sep 04 '15 at 11:58
  • I got rid of the NPE. But, the list items are shifting up and down randomly on scroll. Should I post the code? Thanks for the help :) – krtkush Sep 04 '15 at 13:46
  • I had to combine the answer of this question with your implemenation to make it work - https://stackoverflow.com/questions/28790412/list-view-items-changes-position-when-scrolling-android – krtkush Sep 07 '15 at 13:14