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

Android SharedPreferences保存设置失效 跨Activity读取异常修复

问题排查

你的代码存在4个核心问题,直接导致SharedPreferences存储失效、开关状态不恢复:

  • loadSound()方法仅调用了SP的读取方法,没有把读取到的状态同步给SwitchCompat控件和对应的状态图标,进入设置页自然不会展示上次保存的状态
  • 错误将Activity组件(Settings)作为普通类通过构造方法new Settings(this)创建实例。Activity由系统负责实例化,手动new出来的Activity不具备完整的Context能力,生命周期完全失控,后续调用SP、资源相关方法极易出现异常
  • 存在多处拼写错误:SP文件名常量PREFERRENCE多写了一个r,静音状态值PREFERENCE_SOUND_OFF对应的字符串写为sound_of漏了f,会直接导致读写key/值不匹配
  • 设置SwitchCompat的状态监听前没有先初始化控件状态,设置监听的瞬间会触发一次回调,可能把默认值错误覆盖到SP中
正确实现代码

修复后的Settings Activity

注意:不要给Activity自定义带参数的构造方法,所有需要跨页面访问的常量直接定义为public static即可。

public class Settings extends AppCompatActivity {
    SwitchCompat switchButton;
    ImageView soundIcon;

    // 统一公共常量,修正拼写错误
    public static final String SP_NAME = "game_settings";
    public static final String KEY_SOUND_ENABLED = "sound_enabled";

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

        switchButton = findViewById(R.id.switchButton);
        soundIcon = findViewById(R.id.sound_on);

        // 先加载已保存状态,再设置监听,避免触发无效回调
        loadSettings();

        switchButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
            // 直接存布尔值,不需要转字符串,逻辑更简洁
            getSharedPreferences(SP_NAME, MODE_PRIVATE)
                    .edit()
                    .putBoolean(KEY_SOUND_ENABLED, isChecked)
                    .apply();
            updateSoundUI(isChecked);
        });
    }

    private void loadSettings() {
        SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);
        // 默认声音开启
        boolean soundEnabled = sp.getBoolean(KEY_SOUND_ENABLED, true);
        switchButton.setChecked(soundEnabled);
        updateSoundUI(soundEnabled);
    }

    private void updateSoundUI(boolean isSoundOn) {
        soundIcon.setImageResource(isSoundOn ? R.drawable.sound_on : R.drawable.sound_off);
    }
}

修复后的Quiz Activity调用逻辑

不需要new Settings实例,直接引用Settings类中定义的公共静态常量读取SP即可:

private PlayAudioForAnswers playAudioForAnswers;
private boolean isSoundEnabled;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_quiz);
    playAudioForAnswers = new PlayAudioForAnswers(this);
    loadGameSettings();
}

private void loadGameSettings() {
    SharedPreferences sp = getSharedPreferences(Settings.SP_NAME, MODE_PRIVATE);
    isSoundEnabled = sp.getBoolean(Settings.KEY_SOUND_ENABLED, true);
}

// 需要播放答题音效时直接判断
private void playAnswerAudio(int flag) {
    if (isSoundEnabled) {
        playAudioForAnswers.setAudioforAnswer(flag);
    }
}
开发注意事项
  • 所有系统组件(Activity、Service、BroadcastReceiver等)绝对不要手动通过构造方法创建实例,必须通过系统提供的对应方式(如Intent启动Activity)获取实例,否则会出现Context失效、生命周期混乱等难以排查的问题
  • 给SwitchCompat、CheckBox等带选中状态的控件设置监听器前,必须先给控件设置已保存的选中状态,否则设置监听器时会立刻触发一次选中状态变更回调,导致错误写入默认值
  • 开关类的配置直接用SP的putBoolean/getBoolean存取即可,不需要额外转成字符串,能避免字符串拼写错误、比对逻辑出错等问题
  • SP的key、文件名尽量统一管理为常量,不要在各个页面硬编码字符串,避免拼写不一致导致读写失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:30:51