Android自定义ArrayAdapter中ToggleButton状态保存实现问询
嘿,作为Android入门开发者,你遇到的这个ToggleButton状态保存问题其实很常见,咱们一步步拆解怎么实现,结合你的代码来改更清晰~
核心逻辑梳理
首先得明白:ListView的Item是复用机制(就是你代码里的convertView),滑动的时候旧的Item会被重新填充新数据,如果只依赖ToggleButton本身的状态,滑动后肯定会错乱。所以咱们需要:
- 用一个集合单独存储每个Item的ToggleButton状态,和你的经文数据一一对应
- 把状态持久化到本地(比如SharedPreferences或者你已经用的SQLite数据库),这样APP重启后状态还在
具体实现步骤(结合你的代码)
1. 添加状态存储集合
在你的FullverseAdopter类里添加一个成员变量,用来存储每个位置的ToggleButton状态:
private List<Boolean> toggleStates;
2. 初始化状态集合
在Adapter的构造方法里,初始化这个集合,同时可以从本地读取之前保存的状态(默认设为未选中false):
public FullverseAdopter(ALLVERSE context, int resource, List<String> versenumber, List<String> verselist, List<String> refernce, List<String> verseid) { super(context, resource, versenumber); this.activity = context; this.versenumber = versenumber; this.verselist = verselist; this.refernce = refernce; this.verseid = verseid; // 初始化toggle状态集合,同时读取本地保存的状态 toggleStates = new ArrayList<>(); for (int i = 0; i < versenumber.size(); i++) { // 用verseid作为唯一标识,因为每个经文的id是唯一的 toggleStates.add(getSavedToggleState(verseid.get(i))); } }
3. 实现读取本地状态的辅助方法
添加一个方法,从SharedPreferences里读取之前保存的ToggleButton状态:
private boolean getSavedToggleState(String verseId) { SharedPreferences prefs = activity.getSharedPreferences(MyPREFERENCES, MODE_PRIVATE); // 用"toggle_"+verseid作为key,确保每个经文的状态唯一 return prefs.getBoolean("toggle_" + verseId, false); }
4. 在getView中正确设置ToggleButton状态
在getView方法里,设置ToggleButton的状态时,要从咱们的toggleStates集合里取对应位置的值,而不是用默认值:
// 先设置状态,再设置监听,避免触发不必要的回调 holder.bookmark.setChecked(toggleStates.get(position));
5. 处理ToggleButton状态变化的逻辑
修改你已经写的OnCheckedChangeListener,更新集合状态并持久化到本地,同时处理你的数据库收藏逻辑:
holder.bookmark.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // 第一步:更新内存中的状态集合 toggleStates.set(position, isChecked); // 第二步:持久化到SharedPreferences,确保重启APP后状态还在 SharedPreferences.Editor editor = activity.getSharedPreferences(MyPREFERENCES, MODE_PRIVATE).edit(); editor.putBoolean("toggle_" + verseid.get(position), isChecked); editor.apply(); // 异步保存,比commit更高效 // 第三步:处理你的数据库收藏/取消收藏逻辑 mDBHelper = new DatabaseHelper(activity); mDb = mDBHelper.getWritableDatabase(); if (isChecked) { // 添加到收藏数据库 ContentValues contentValues = new ContentValues(); contentValues.put("id", verseid.get(position)); contentValues.put("bookname", refernce.get(position)); contentValues.put("versenumber", versenumber.get(position)); contentValues.put("verse", verselist.get(position)); long check = mDb.insert("favourite", null, contentValues); Log.d("MY_TAG", "Added to favourite: " + check); Toasty.success(activity, "Added to favourite", Toast.LENGTH_SHORT, true).show(); } else { // 从收藏数据库删除 long delete = mDb.delete("favourite", "id=?", new String[]{verseid.get(position)}); Log.d("MY_TAG", "Removed from favourite: " + delete); Toasty.error(activity, "Removed from favourite", Toast.LENGTH_SHORT, true).show(); } // 记得关闭数据库连接,避免内存泄漏 mDb.close(); mDBHelper.close(); } });
6. 注意避坑
- 不要在getView里重复创建TextToSpeech:你现在每次getView都new一个TextToSpeech,会导致严重的内存泄漏!建议把TextToSpeech的初始化放到你的
ALLVERSEActivity里,或者在Adapter的构造方法里初始化一次。 - 数据库连接要及时关闭:上面的代码里我加了
mDb.close()和mDBHelper.close(),不然会浪费资源。 - 状态设置要在监听之前:先调用
setChecked再设置OnCheckedChangeListener,避免刚设置状态就触发回调。
这样改完之后,你的ToggleButton状态就不会因为ListView滑动而错乱,而且重启APP后之前的状态也能保留啦~
内容的提问来源于stack exchange,提问作者user10968638
相关产品推荐
相关产品推荐

