【问题标题】:Error saving checked state of checkbox in custom listview在自定义列表视图中保存复选框的选中状态时出错
【发布时间】:2016-12-03 22:52:05
【问题描述】:

我想在我的列表视图中保存复选框的选中状态,以便当我转到另一个活动然后返回此活动时,选定的复选框应该保持选中状态。我使用自定义适配器来显示 2 种类型的布局。我使用 sparsebooleanarray 和 sharedpreference 来保存选中状态。这在使用 List 时有效,但在使用 List 时出现 NullPointerException。有什么办法可以保存这里的状态吗?

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

【问题讨论】:

标签: android listview android-sharedpreferences


【解决方案1】:

如果我们去grep code,我们会看到:

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

我们记得,您在调用 listView.getCheckedItemPositions() 时收到 null。所以我认为可能是因为你没有使用listView.setChoiceMode

【讨论】:

  • 我更新了我的代码。我包括了 Choicemode,它现在没有崩溃。但它仍然没有保留状态@Michael
  • 您是否检查过检查状态是否已保存?
  • 如何检查?
  • 通过onDestroy 方法使用调试器。在stringSet 中检查您是否拥有所有已检查的职位。然后使用调试器执行 onCreate 并检查共享首选项是否包含 "checked_items"
  • 在 onDestroy 中,我检查了 stringSet 的包含值,如下所示:String[] array = stringSet.toArray(new String[0]); System.out.println("The Array" + Arrays.toString(array)); 但我在 LogCat 中得到了这样的结果:I/System.out: The Array[]@Michael
【解决方案2】:

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

【讨论】:

  • 实际上,正如我在对@Michael 的最后评论中提到的,当我单击返回按钮但我没有得到检查状态值时,onDestroy() 方法正在触发
  • 当单击此活动中的后退按钮时,onDestroy 会触发但不会触发导航。如果您想获取已检查的项目,可以尝试使用 items.get(position).isBox() 从项目列表中获取它们
  • 您能告诉我如何以及在哪里执行此操作吗?是在适配器还是在活动中?
  • 我尝试了您的建议,但仍然无法正常工作@faranjit
猜你喜欢
  • 1970-01-01
  • 2013-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 2020-10-06
相关资源
最近更新 更多