You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义ArrayAdapter中ToggleButton状态保存实现问询

解决自定义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的初始化放到你的ALLVERSE Activity里,或者在Adapter的构造方法里初始化一次。
  • 数据库连接要及时关闭:上面的代码里我加了mDb.close()和mDBHelper.close(),不然会浪费资源。
  • 状态设置要在监听之前:先调用setChecked再设置OnCheckedChangeListener,避免刚设置状态就触发回调。

这样改完之后,你的ToggleButton状态就不会因为ListView滑动而错乱,而且重启APP后之前的状态也能保留啦~

内容的提问来源于stack exchange,提问作者user10968638

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:25:10