0

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);

}
BillUser88
  • 127
  • 1
  • 3
  • 16

1 Answers1

0

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;
    }
kris larson
  • 30,387
  • 5
  • 62
  • 74
  • Thank you very much for your code, you really helped me to understand some things. Now with this code i have managed to check one and uncheck the others which is perfect but now i have lost the state.Any quick fix? and also why null there? sw.setOnCheckedChangeListener(null) – BillUser88 Feb 11 '16 at 00:58
  • Not sure I understand what you mean by "lost the state". If you are using the preferences to store the state of the whole list, there's probably a better way. As for null, just calling `setChecked` will fire the `OnCheckedChangeListener`, so by setting it to null you make sure that it only gets fired when the user checks/unchecks it. Remember, these views can be recycled so the view may come in with the listener already set; that's why you need to unset it first. – kris larson Feb 11 '16 at 02:28
  • i mean that when i return to the activity again the switch is not on but off so it lost its state. is this Arrays.fill(checkedStatus, false); causing the problem? what do you mean by there is a better way? – BillUser88 Feb 11 '16 at 10:15
  • If you just need to persist state between orientation changes and returns from other activities, you can use `onSaveInstanceState()` to save the current switch settings. If it needs to be persistent beyond that, preferences is okay, but a database table might be better. You can use the preferences to restore your state; post your activity code that creates the boolean array and the adapter; then I will update my answer. – kris larson Feb 11 '16 at 14:36
  • i have updated my post with the activity you asked. What can i do now? – BillUser88 Feb 11 '16 at 15:34
  • I updated my answer. I added the matching restore code for the preference saving code I posted earlier. It just retrieves the index of the checked switch and sets that boolean to true. – kris larson Feb 12 '16 at 01:59
  • I was surprised to see that you are using a database to retrieve goal data, yet you are storing the state in preferences. What if the data in the table changes? The index in the preferences won't be pointing at the correct row anymore. This is what I meant by a better way of saving state. If you could update your database data model to include the user's current state, everything could be internally consistent and you wouldn't have to worry about the preferences getting out of sync with the database. Also, you could use a `CursorAdapter` and simplify the adapter code a bit. – kris larson Feb 12 '16 at 02:05
  • Thanks for the options you mention. One minor issue now is that the array is not filling with values so i have null pointer exception. – BillUser88 Feb 12 '16 at 14:25