如何将CheckBox选中状态保存到Room数据库并解决重启应用状态丢失问题
核心问题
共3处错误导致状态未持久化:
- 列表中CheckBox的选中变更事件没有关联数据库更新逻辑
- MainActivity中监听的CheckBox是单独inflate出来的无效View,和RecyclerView实际渲染的条目完全无关
- 执行更新操作时新建的Todo对象没有携带原有主键ID,Room的
@Update逻辑依赖主键匹配数据,找不到对应行自然不会执行更新
修复方案
1. 修改TodoAdapter,新增状态变更回调
给Adapter添加回调接口,在CheckBox选中事件触发时把修改后的Todo实体回传给调用层:
public class TodoAdapter extends RecyclerView.Adapter<TodoAdapter.ViewHolder>{ private List<Todo> todos = new ArrayList<>(); // 新增回调接口 public interface OnCheckedChangeListener { void onCheckedChanged(Todo todo); } private OnCheckedChangeListener listener; public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { this.listener = listener; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ViewHolder(TodoItemBinding.inflate(LayoutInflater.from(parent.getContext()),parent,false)); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Todo currentTodo = todos.get(holder.getAbsoluteAdapterPosition()); holder.binding.tvTitle.setText(currentTodo.getTitle()); holder.binding.checkBox.setChecked(currentTodo.getChecked()); holder.binding.checkBox.setOnCheckedChangeListener(null); holder.binding.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // 更新当前Todo的选中状态 currentTodo.setChecked(isChecked); // 触发回调 if (listener != null) { listener.onCheckedChanged(currentTodo); } } }); } @Override public int getItemCount() { return todos == null ? 0 : todos.size(); } public void setTodos(List<Todo> todos){ this.todos = todos; notifyDataSetChanged(); } class ViewHolder extends RecyclerView.ViewHolder{ private TodoItemBinding binding; public ViewHolder(TodoItemBinding bind){ super(bind.getRoot()); this.binding = bind; } } }
2. 修改MainActivity,清理无效代码实现回调
删除所有和todoItemBinding相关的代码(包括初始化、CheckBox点击监听逻辑),给Adapter设置回调处理数据库更新:
public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; private TodoViewModel todoViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); View view = binding.getRoot(); setContentView(view); RecyclerView recyclerView = binding.recyclerView; recyclerView.setLayoutManager(new LinearLayoutManager(this)); TodoAdapter todoAdapter = new TodoAdapter(); recyclerView.setAdapter(todoAdapter); todoViewModel = new ViewModelProvider(this).get(TodoViewModel.class); todoViewModel.getTodo().observe(this, new Observer<List<Todo>>() { @Override public void onChanged(List<Todo> todos) { todoAdapter.setTodos(todos); } }); // 设置CheckBox状态变更回调 todoAdapter.setOnCheckedChangeListener(new TodoAdapter.OnCheckedChangeListener() { @Override public void onCheckedChanged(Todo todo) { // 直接用传入的已有ID的Todo对象执行更新 todoViewModel.update(todo); } }); binding.btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { addTodo(); } }); } private void addTodo() { String title = binding.editText.getText().toString().trim(); if (title.isEmpty()) { return; } Todo todo = new Todo(title,false); todoViewModel.insert(todo); binding.editText.setText(""); closeKeyboard(); } private void closeKeyboard(){ View view = this.getCurrentFocus(); if (view != null) { InputMethodManager manager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); manager.hideSoftInputFromWindow(view.getWindowToken(), 0); } } }
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

