0

I want to save the checked state of checkbox in my listview so that when I go to another activity and then come back to this activity, the selected checkoxes should remain selected. I've used a custom adapter to display 2 types of layout. I used sparsebooleanarray and sharedpreference to save the checked state. This works when using List but I'm getting NullPointerException when I use List. Is there any way to save the state here?

public class ListViewActivity extends AppCompatActivity {

    SharedPreferences sharedPreferences;
    ListView listView;

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

        listView = (ListView) findViewById(R.id.listview);

        List<Item> items = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            items.add(new Item("I am TextView layout #" + i, Item.TYPE_TEXTVIEW, false));
            items.add(new Item("I am ImageView layout #" + i, Item.TYPE_IMAGEVIEW, false));
        }

        MultipleLayoutAdapter adapter = new MultipleLayoutAdapter(this, items);
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        listView.setAdapter(adapter);

        sharedPreferences = getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE);



        Set<String> checkedItemsSource = sharedPreferences.getStringSet("checked_items", new HashSet<String>());
        SparseBooleanArray checkedItems = convertToCheckedItems(checkedItemsSource);
        for (int i = 0; i < checkedItems.size(); i++) {
            int checkedPosition = checkedItems.keyAt(i);
            listView.setItemChecked(checkedPosition, true);
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        SparseBooleanArray checkedItems = listView.getCheckedItemPositions();
////got exception here
        Set<String> stringSet = convertToStringSet(checkedItems);
        sharedPreferences.edit()
                .putStringSet("checked_items", stringSet)
                .apply();
    }

    private SparseBooleanArray convertToCheckedItems(Set<String> checkedItems) {
        SparseBooleanArray array = new SparseBooleanArray();
        for(String itemPositionStr : checkedItems) {
            int position = Integer.parseInt(itemPositionStr);
            array.put(position, true);
        }

        return array;
    }

    private Set<String> convertToStringSet(SparseBooleanArray checkedItems) {
        Set<String> result = new HashSet<>();
////got exception here
        for (int i = 0; i < checkedItems.size(); i++) {
            result.add(String.valueOf(checkedItems.keyAt(i)));
        }

        return result;
    }
}


public class MultipleLayoutAdapter extends BaseAdapter {

    private Context    context;
    private List<Item> items;

    public MultipleLayoutAdapter(Context context, List<Item> items) {
        this.context = context;
        this.items = new ArrayList<>(items);
    }

    @Override
    public int getCount() {
        return items.size();
    }

    @Override
    public Item getItem(int position) {
        return items.get(position);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {
        return getItem(position).getType();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Item item = getItem(position);
        int viewType = getItemViewType(position);
        switch (viewType) {

            case Item.TYPE_TEXTVIEW:
                convertView = inflateTextView(convertView, parent, item);
                break;

            case Item.TYPE_IMAGEVIEW:
                convertView = inflateImageView(convertView, parent, item);
                break;
        }
        return convertView;
    }


    private View inflateTextView(View convertView, ViewGroup parent, Item item) {
        TextViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.textview_list_row, parent, false);
            viewHolder = new TextViewHolder(convertView);
            convertView.setTag(viewHolder);
        }
        else {
            viewHolder = (TextViewHolder) convertView.getTag();
        }

        viewHolder.textView.setText(item.getData());
        viewHolder.checkBox.setChecked(item.isBox());

        return convertView;
    }

    private View inflateImageView(View convertView, ViewGroup parent, Item item) {
        ImageViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.imageview_list_row, parent, false);
            viewHolder = new ImageViewHolder(convertView);
            convertView.setTag(viewHolder);
        }
        else {
            viewHolder = (ImageViewHolder) convertView.getTag();
        }

        viewHolder.textView.setText(item.getData());
        viewHolder.checkBox.setChecked(item.isBox());


        return convertView;
    }




    static class TextViewHolder {
        private TextView textView;
        private CheckBox checkBox;

        public TextViewHolder(View convertView) {
            this.textView = (TextView) convertView.findViewById(R.id.textview);
            this.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
        }
    }

    static class ImageViewHolder {
        private ImageView imageView;
        private TextView  textView;
        private CheckBox checkBox;

        public ImageViewHolder(View convertView) {
            this.imageView = (ImageView) convertView.findViewById(R.id.imageview);
            this.textView = (TextView) convertView.findViewById(R.id.textview);
            this.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
        }
    }

}

public class Item {
    public static final int TYPE_TEXTVIEW  = 0;
    public static final int TYPE_IMAGEVIEW = 1;

    private String data;
    private int    type;
    private boolean box;
    private Context context;

    public Item(Context context) {
        this.context = context;
    }

    public Item(String data, int type, boolean box) {
        this.data = data;
        this.type = type;
        this.box = box;
    }

    public String getData() {
        return data;
    }

    public int getType() {
        return type;
    }

    public boolean isBox() {
        return box;
    }

    public void setBox(boolean box) {
        this.box = box;
    }
}
CodeAssasins
  • 237
  • 5
  • 17
  • 1
    I think you should cut the code down to a minimal example, and point out where the error occurs. – Eiko Jul 29 '16 at 09:29
  • Possible duplicate of [How to get selected list items from a Listview with checkBox and Custom Adapter?](http://stackoverflow.com/questions/10911361/how-to-get-selected-list-items-from-a-listview-with-checkbox-and-custom-adapter) – Vishal Thakkar Jul 29 '16 at 09:32
  • The link you provided doesn't have anything to save checked statte @AndroidDeveloper – CodeAssasins Jul 29 '16 at 09:40
  • I've edited my code to show where I'm getting the error and here is the logcat link http://www.hastebin.com/mamecibupa.avrasm @Eiko – CodeAssasins Jul 29 '16 at 09:43
  • Did you provide choice mode for list view? – Michael Spitsin Jul 29 '16 at 09:46

2 Answers2

0

If we go to grep code, we will see:

public SparseBooleanArray More ...getCheckedItemPositions() {
    if (mChoiceMode != CHOICE_MODE_NONE) {
        return mCheckStates;
    }
    return null;
}

And we remember, that you recieve null, when calling listView.getCheckedItemPositions(). So I think it could be, because you didn't use listView.setChoiceMode.

Michael Spitsin
  • 2,539
  • 2
  • 19
  • 29
  • I updated my code. I included Choicemode and its now not crashing. But it still not retaining the state @Michael – CodeAssasins Jul 29 '16 at 09:55
  • Did you checked that checked state is saved? – Michael Spitsin Jul 29 '16 at 10:01
  • How to check that? – CodeAssasins Jul 29 '16 at 10:03
  • Go with debugger through `onDestroy` method. Check that in `stringSet` you have all positions, that you checked. And then go through onCreate with debugger and check, that shared prefs contains `"checked_items"` – Michael Spitsin Jul 29 '16 at 10:06
  • in onDestroy, I checked the contained values of `stringSet` like this: `String[] array = stringSet.toArray(new String[0]); System.out.println("The Array" + Arrays.toString(array));` But I got result in LogCat like this: `I/System.out: The Array[]` @Michael – CodeAssasins Jul 29 '16 at 13:59
  • Because you try to paste list items into empty array. Please read about debug mode (green bug in IDE) and mark your method with break point then go through it with debug method – Michael Spitsin Jul 29 '16 at 18:57
0

MultipleLayoutAdapter

public class MultipleLayoutAdapter extends BaseAdapter {

private Context context;
private List<Item> items;

public MultipleLayoutAdapter(Context context, List<Item> items) {
    this.context = context;
    this.items = new ArrayList<>(items);
}

@Override
public int getCount() {
    return items.size();
}

@Override
public Item getItem(int position) {
    return items.get(position);
}

@Override
public long getItemId(int i) {
    return i;
}

@Override
public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {
    return getItem(position).getType();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Item item = getItem(position);
    int viewType = getItemViewType(position);
    switch (viewType) {

        case Item.TYPE_TEXTVIEW:
            convertView = inflateTextView(convertView, parent, item);
            break;

        case Item.TYPE_IMAGEVIEW:
            convertView = inflateImageView(convertView, parent, item);
            break;
    }
    return convertView;
}


private View inflateTextView(View convertView, ViewGroup parent, final Item item) {
    TextViewHolder viewHolder;
    if (convertView == null) {
        convertView = LayoutInflater.from(context).inflate(R.layout.textview_list_row, parent, false);
        viewHolder = new TextViewHolder(convertView);
        convertView.setTag(viewHolder);
    }
    else {
        viewHolder = (TextViewHolder) convertView.getTag();
    }

    viewHolder.textView.setText(item.getData());

    viewHolder.checkBox.setOnCheckedChangeListener(null);
    viewHolder.checkBox.setChecked(item.isBox());
    viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            item.setBox(b);
        }
    });

    return convertView;
}

private View inflateImageView(View convertView, ViewGroup parent, final Item item) {
    ImageViewHolder viewHolder;
    if (convertView == null) {
        convertView = LayoutInflater.from(context).inflate(R.layout.imageview_list_row, parent, false);
        viewHolder = new ImageViewHolder(convertView);
        convertView.setTag(viewHolder);
    }
    else {
        viewHolder = (ImageViewHolder) convertView.getTag();
    }

    viewHolder.textView.setText(item.getData());

    viewHolder.checkBox.setOnCheckedChangeListener(null);
    viewHolder.checkBox.setChecked(item.isBox());
    viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            item.setBox(b);
        }
    });


    return convertView;
}




static class TextViewHolder {
    private TextView textView;
    private CheckBox checkBox;

    public TextViewHolder(View convertView) {
        this.textView = (TextView) convertView.findViewById(R.id.textview);
        this.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
    }
}

static class ImageViewHolder {
    private ImageView imageView;
    private TextView textView;
    private CheckBox checkBox;

    public ImageViewHolder(View convertView) {
        this.imageView = (ImageView) convertView.findViewById(R.id.imageview);
        this.textView = (TextView) convertView.findViewById(R.id.textview);
        this.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
    }
}

}

MainActivity

public class MainActivity extends AppCompatActivity {

SharedPreferences sharedPreferences;
ListView listView;
List<Item> items = new ArrayList<>();
MultipleLayoutAdapter adapter;

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

    listView = (ListView) findViewById(R.id.listview);

    for (int i = 1; i <= 10; i++) {
        items.add(new Item("I am TextView layout #" + i, Item.TYPE_TEXTVIEW, false));
        items.add(new Item("I am ImageView layout #" + i, Item.TYPE_IMAGEVIEW, false));
    }

    findViewById(R.id.btn_go).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            startActivity(new Intent(MainActivity.this, Main2Activity.class));
        }
    });
}

@Override
protected void onResume() {
    super.onResume();

    sharedPreferences = getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE);
    Set<String> checkedItemsSource = sharedPreferences.getStringSet("checked_items", new HashSet<String>());
    SparseBooleanArray checkedItems = convertToCheckedItems(checkedItemsSource);

    for (int i = 0; i < checkedItems.size(); i++) {
        int checkedPosition = checkedItems.keyAt(i);
        items.get(checkedPosition).setBox(true);
    }

    if (adapter == null) {
        adapter = new MultipleLayoutAdapter(this, items);
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        listView.setAdapter(adapter);
    } else {
        adapter.notifyDataSetChanged();
    }
}

@Override
protected void onPause() {
    Set<String> stringSet = new HashSet<>();
    for (int i = 0; i < items.size(); i++) {
        if (items.get(i).isBox()) {
            stringSet.add(String.valueOf(i));
        }
    }

    sharedPreferences.edit()
            .putStringSet("checked_items", stringSet)
            .apply();

    super.onPause();
}

private SparseBooleanArray convertToCheckedItems(Set<String> checkedItems) {
    SparseBooleanArray array = new SparseBooleanArray();
    for (String itemPositionStr : checkedItems) {
        int position = Integer.parseInt(itemPositionStr);
        array.put(position, true);
    }

    return array;
}

private Set<String> convertToStringSet(SparseBooleanArray checkedItems) {
    Set<String> result = new HashSet<>();
    for (int i = 0; i < checkedItems.size(); i++) {
        result.add(String.valueOf(checkedItems.keyAt(i)));
    }

    return result;
}
}
faranjit
  • 1,567
  • 1
  • 15
  • 22
  • Actually as mentioned in my last comment to @Michael, onDestroy() method is firing when I click back button but I'm not getting checked state values – CodeAssasins Jul 29 '16 at 14:21
  • When click back button in this activity onDestroy fires but not fires navigating. If you want to get checked items you can try get them from item list using items.get(position).isBox() – faranjit Jul 29 '16 at 14:33
  • Could you show me how and where to do this? Is it in adapter or activity? – CodeAssasins Jul 29 '16 at 14:41
  • I tried what you suggested but still its not working @faranjit – CodeAssasins Aug 01 '16 at 04:45