lundi 13 juillet 2015

ExpandableListView involuntarily toggling CheckBoxes/ changing values when not in view?

I am creating an ExpandableListView with CheckBoxes in the childViews, all contained in a NavigationDrawer. I have set up ArrayList matrices and SugarRecord databases to record and save each checked value. The ExpandableListView is especially frustrating because moving items out of view by collapsing groups or scrolling items off the screen, the values can involuntarily change/ checkboxes involuntarily toggle.

Previously, I was having the issue I outlined here: Overlap of children in ExpandableListView involuntarily causes checkboxes to check in separate groups ...but everything I came short on that was causing the previous problem is solved (to my knowledge) now that I've cleaned up the adapter and approached the data display in a much more organized fashion.

Now, I don't know what's causing the checkboxes to toggle other than them being off screen. Here's what I have noticed:

  • When just one group is expanded (Assignments), I can toggle any CheckBox, scroll it out of view, collapse it, and nothing will change involuntarily. This is good... I hope.
  • When I expand 'Archived' and slide up and down so some/none of each item from either group is showing, the toggling seems almost random.
  • What does seem to influence a pattern in the toggling is what is selected in the 'Archived' group (whether or not it is expanded when the sliding-toggling phenomenon happens).

If pictures are desired, just let me know. The issue is very hard to capture in screenshots, but if it helps to clarify what the issue actually is, I'd be glad to include that along with my code.

Here is my code:

Adapter Class

@SuppressWarnings("unchecked")
public class NewAdapter extends BaseExpandableListAdapter {
    public ArrayList<String> groupItem;
    public ArrayList<SubjectInfo> tempChild;
    public ArrayList<ArrayList<SubjectInfo>> childItemList = new ArrayList<ArrayList<SubjectInfo>>();
    //childItemList is an ArrayList of ArrayLists!!
    public LayoutInflater minflater;
    public Activity activity;
    private final Context context;

    private CompoundButton.OnCheckedChangeListener myCheckChangedListener =
        new CompoundButton.OnCheckedChangeListener() {

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        //Update SugarRecord value for SubjectInfo
        SubjectInfo si = SubjectInfo.findById(SubjectInfo.class,
                (Long.valueOf((Integer)(buttonView.getTag(R.string.si_array_index_key)))+1));
        //because indices start at 1 in SugarRecord
        if (si.subjectChecked != isChecked) {
            si.subjectChecked = isChecked;
            childItemList.get((int)buttonView.getTag(R.string.group_position_key))
                    .set((int) buttonView.getTag(R.string.child_position_key), si);
            //change ArrayList <<>> value
            si.save();
            notifyDataSetChanged();
            Toast.makeText(NewAdapter.this.context, "Toggled " +isChecked,
                    Toast.LENGTH_SHORT).show();
        } else {
            int throwErrorplz = 10/0;
        }
    }
    };


    public NewAdapter(Context context,ArrayList<String> grList,
                  ArrayList<ArrayList<SubjectInfo>> childItemList) {
    this.context = context;
    groupItem = grList;
    this.childItemList = childItemList;
    //and each child is an ArrayList
}

public void setInflater(LayoutInflater mInflater, Activity act) {
    this.minflater = mInflater;
    activity = act;
}

@Override
public Object getChild(int groupPosition, int childPosition) {
    return childItemList.get(groupPosition).get(childPosition);
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return childPosition;
}

@Override
public View getChildView(int groupPosition, final int childPosition,
                         boolean isLastChild, View convertView, ViewGroup parent)
{
    //child is a list! so is tempChild... etc
    tempChild = (ArrayList<SubjectInfo>) childItemList.get(groupPosition);
    TextView text = null;
    CheckBox cBox = null;

    if (convertView == null)
    {   LayoutInflater layoutInflater = (LayoutInflater)context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.drawer_submenu_item,parent,false);
    }
    text = (TextView) convertView.findViewById(R.id.submenu_textView);
    cBox = (CheckBox) convertView.findViewById(R.id.show_child_subject_checkBox);
    text.setText(tempChild.get(childPosition).subjectName);
    cBox.setChecked(tempChild.get(childPosition).subjectChecked);
    List<SubjectInfo> sil = SubjectInfo.listAll(SubjectInfo.class);
    for (int go = 0; go < sil.size(); go++) {
        if (sil.get(go).subjectName.equals(tempChild.get(childPosition).subjectName)) {
            cBox.setTag(R.string.group_position_key, groupPosition);
            cBox.setTag(R.string.si_array_index_key, go);
            cBox.setTag(R.string.child_position_key, childPosition);
        }
    }//to find the index for ArrayList and SugarRecord DB update data
    cBox.setOnCheckedChangeListener(myCheckChangedListener);
    convertView.setTag(tempChild.get(childPosition));
    return convertView;
}


@Override
public int getChildrenCount(int groupPosition) {
    return childItemList.get(groupPosition).size();
}

@Override
public Object getGroup(int groupPosition) {
    return childItemList.get(groupPosition);
}

@Override
public int getGroupCount() {
    return groupItem.size();
}

@Override
public void onGroupCollapsed(int groupPosition) {
    super.onGroupCollapsed(groupPosition);
}

@Override
public void onGroupExpanded(int groupPosition) {
    super.onGroupExpanded(groupPosition);
}

@Override
public long getGroupId(int groupPosition) {
    return 0;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
    if (convertView == null)
    {
        LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.drawer_group_item,parent,false);

    }

    ((TextView) convertView).setText(groupItem.get(groupPosition));
    //Header Title
    convertView.setTag(groupItem.get(groupPosition));
    return convertView;
}

@Override
public boolean hasStableIds() {
    return false;
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true; //was false, and was why toast wasn't presenting. Now that True, it does.
}
}

MainActivity if you will...

@SuppressLint("NewApi")
public class MainNavigationActivity extends ActionBarActivity implements OnChildClickListener {

private DrawerLayout drawer;
private ExpandableListView drawerList;
private CheckBox checkBox;
private ActionBarDrawerToggle actionBarDrawerToggle;
public ArrayList<String> groupItem = new ArrayList<String>();
public ArrayList<ArrayList<SubjectInfo>> childItem = new ArrayList<ArrayList<SubjectInfo>>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_drawer_layout_test);

    setGroupData();
    setChildGroupData();

    initDrawer();
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.drawer_layout_test, menu);
    return true;
}

private void initDrawer() {
    drawer = (DrawerLayout) findViewById(R.id.drawer_layout2);
    drawerList = (ExpandableListView) findViewById(R.id.left_drawer2);
    drawerList.setAdapter(new NewAdapter(this, groupItem, childItem));
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
        drawerList.setIndicatorBounds(310, 350);
    } else {
        drawerList.setIndicatorBoundsRelative(310, 350);
    }


    drawerList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v,
                                    int groupPosition, long id){
            Fragment fragment;
            FragmentManager fragmentManager;
            Bundle args;
            switch (groupPosition) {
                case 0:
                    fragment = new AssignmentManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(AssignmentManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_SHORT).show();
                    break;

                case 1:
                    fragment = new AssignmentManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(AssignmentManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_SHORT).show();
                    break;

                case 2:
                    fragment = new SubjectManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(SubjectManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_SHORT).show();
                    drawer.closeDrawer(drawerList);
                    break;

                // for now, just SubjectManager, but soon they will lead to Settings then H/Feedback
                case 3:
                    fragment = new SubjectManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(SubjectManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_LONG).show();
                    break;

                case 4:
                    fragment = new SubjectManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(SubjectManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_LONG).show();
                    break;
            }
            return true;
        }

    });

    drawerList.setOnChildClickListener(this);


    actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, R.string.drawer_open,
            R.string.drawer_close) {
        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);
            getSupportActionBar().setTitle("open");
            invalidateOptionsMenu();
        }

         // Called when a drawer has settled in a completely open state.

        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);
            getSupportActionBar().setTitle("close");
            invalidateOptionsMenu();
        }
    };

    drawer.setDrawerListener(actionBarDrawerToggle);
    actionBarDrawerToggle.setDrawerIndicatorEnabled(true);
    actionBarDrawerToggle.syncState();

}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    // Sync the toggle state after onRestoreInstanceState has occurred.
    actionBarDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    actionBarDrawerToggle.onConfigurationChanged(newConfig);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Pass the event to ActionBarDrawerToggle, if it returns
    // true, then it has handled the app icon touch event
    if (actionBarDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle your other action bar items...

    return super.onOptionsItemSelected(item);
}

public void setGroupData() {
    groupItem.add("Assignments");
    groupItem.add("Archived");
    groupItem.add("Subjects");
    groupItem.add("Settings");
    groupItem.add("Help / Feedback");
}

public void setChildGroupData() {
    /**
     * Add Data For Assignments and Archived
     */

    ArrayList<SubjectInfo> childAssignments = new ArrayList<SubjectInfo>();
    ArrayList<SubjectInfo> childArchived = new ArrayList<SubjectInfo>();
    List<SubjectInfo> sil = SubjectInfo.listAll(SubjectInfo.class);

    for (int go = 0; go < sil.size(); go++) {
        if (sil.get(go).itemHeaderTitle.equals("Assignments")) {
            childAssignments.add(sil.get(go));
        }
        else {
            childArchived.add(sil.get(go));
        }
    }
    childItem.add(childAssignments);
    if (childArchived.size() == 0) {
        childArchived.add(new SubjectInfo("Archived", "Archived", 888, true, true));
        childArchived.add(new SubjectInfo("Completed", "Archived", 888, true, true));
        childArchived.add(new SubjectInfo("Outdated", "Archived", 888, true, true));
        childArchived.get(0).save();
        childArchived.get(1).save();
        childArchived.get(2).save();
    }
    childItem.add(childArchived);

    /**
     * Add empty children for Subjects, Settings, and H/Feedback
     */
    ArrayList<SubjectInfo> child;

    child = new ArrayList<SubjectInfo>(); //essentially null
    childItem.add(child);
    childItem.add(child);
    childItem.add(child);
}

@Override
public boolean onChildClick(ExpandableListView parent, View v,
                            int groupPosition, final int childPosition, long id) {
    checkBox = (CheckBox) v.findViewById(R.id.show_child_subject_checkBox);
    checkBox.toggle();
    Toast.makeText(getApplicationContext(), "Toggled " +groupPosition + "|" + childPosition,
            Toast.LENGTH_SHORT).show();
    // the oncheckedchangedListener now resides and operates out of adapter
    // in a much more efficient, clean manner
    return true;
}
}




Aucun commentaire:

Enregistrer un commentaire