Search code examples
androidoncheckedchanged

How can i have one switch on in a ListView of many switches?


I am building an Android app and I would like to have active only one switch in on-mode at any time in a ListView. I am using the onCheckedChanged method. How can I do this?

public ListAdapter2(Context context, ArrayList<String> resource, Boolean[] checkedStatus) {
    super(context,R.layout.toggle_button_row,resource);
    // TODO Auto-generated constructor stub
    this.context = context;
    goalList=new ArrayList<String>();
    this.goalList =resource;
    this.checkedStatus=checkedStatus;

}

 @Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    convertView = inflater.inflate(R.layout.toggle_button_row, parent, false);
    v1=convertView;
    TextView name = (TextView) v1.findViewById(R.id.textview1);
    name.setText(goalList.get(position).toString());
    sw= (Switch) v1.findViewById(R.id.switch1);
    sw.setTag(position);
    sw.setOnCheckedChangeListener(ListAdapter2.this);
    sw.setChecked(checkedStatus[position]);

    return convertView;
}

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    Integer index = (Integer) buttonView.getTag();
    checkedStatus[index] = isChecked;
    String key = index.toString();

    //save the data for the status
    SharedPreferences sharedPreferences = getContext().getSharedPreferences("status", Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putBoolean(key, isChecked);
    editor.putBoolean("MyGoal", isChecked);
    editor.putString("MyGoal1", goalList.get(index).toString().trim());
    editor.apply();
}

I have added more of my code. What i want to do is this, in this specific ListView when i switched on for example the first one i want to save its state and i have accomplished this by using sharedPreferences but i dont want to have multiple switches on. So when i activate the second one i want the first one to to become off. The same applies to all of them, when one is active the others are off.

public void display(View v) {
    //The database is open!
    ExternalDbOpenHelper dbOpenHelper = new ExternalDbOpenHelper(this, DB_NAME);
    database = dbOpenHelper.openDataBase();
    //initialize
    goalList = new ArrayList<String>();
    //put cursor
    Cursor cursor = database.rawQuery("select * from tbl_WG", null);
    cursor.moveToFirst();
    if(!cursor.isAfterLast()) {
        do {
            String name=cursor.getString(cursor.getColumnIndex("name"));
            Integer steps=Integer.parseInt(cursor.getString(1));

            goalList.add("Name: "+name+" || Steps: "+steps);


        } while (cursor.moveToNext());
    }
    cursor.close();
    //size of the status list;
    status= new boolean[goalList.size()];

    //check state
    SharedPreferences sharedPreferences = getSharedPreferences("status", MODE_PRIVATE);
    checkedStatus = new Boolean[goalList.size()];
    for ( int index = 0; index < checkedStatus.length; index++)
        checkedStatus[index] = sharedPreferences.getBoolean(Integer.toString(index), false);


    //create an ArrayAdaptar from the String Array
    ListAdapter2 adapter = new ListAdapter2(this, goalList, checkedStatus);
    // Assign adapter to ListView
    mainListView.setAdapter(adapter);

}

Solution

  • I think you're almost there.

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    
            // First turn off the switch of any other item that may be on
            Arrays.fill(checkedStatus, false);
    
            Integer index = (Integer) buttonView.getTag();
            checkedStatus[index] = isChecked;
            notifyDataSetChanged();  // don't forget to tell ListView that data is updated
    
            //save the data for the status
            String key = index.toString();
            SharedPreferences sharedPreferences = getContext().getSharedPreferences("status", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = sharedPreferences.edit();
    
            /*
             *  I don't think this code:
             *
             *      editor.putBoolean(key, isChecked);
             *
             *  is a really good idea, because you have to make sure
             *  you "uncheck" any keys that were previously checked.
             *
             *  This might be better:
             */
            if (isChecked) {
                editor.putInt("last_index", index);
            } else {
                editor.remove("last_index"); // nothing's checked, so erase pref
            }
    
            editor.putBoolean("MyGoal", isChecked);
    
            // not sure this makes sense if isChecked == false, you may want to rethink the preferences
            editor.putString("MyGoal1", goalList.get(index).toString().trim());
            editor.apply();
        }
    

    Also, in your getView method, you should do something like this:

            sw.setOnCheckedChangeListener(null);
            sw.setChecked(checkedStatus[position]);
            sw.setOnCheckedChangeListener(ListAdapter2.this);
    

    This will prevent any recycled listeners from firing when you're setting the checked state of the switch.


    With the preference saving code above, here's how you can restore the checked state:

        //check state
        SharedPreferences sharedPreferences = getSharedPreferences("status", MODE_PRIVATE);
        checkedStatus = new Boolean[goalList.size()];
        int index = sharedPreferences.getInt("last_index", -1);
        if (index != -1) {
            checkedStatus[index] = true;
        }