Android/Java SharedPreferences持久化Vector Assets货币设置
问题根因
你的货币选择配置实际上已经写入了SharedPreferences,重启后重置是代码逻辑错误导致的,核心问题有4个:
- 字符串比较逻辑完全失效:Java中
==比较的是对象内存地址,不是字符串实际内容。你所有判断货币类型的分支都用==匹配固定字符串,但从SharedPreferences读取出来的字符串是独立的新对象,和代码中写的字符串常量内存地址不一致,所有判断分支都不会命中,图标设置逻辑不执行,看起来像是配置重置回了默认。 - SharedPreferences键值冲突:你使用同一个
PREF_CURRENCY_VALUE键先后存储字符串、整数类型值,后写入的int值会覆盖之前的字符串值,导致读取结果不符合预期。 - 监听器绑定逻辑冗余:你在Spinner的
onItemSelected回调里反复给保存按钮绑定点击事件,会导致多个监听器叠加,执行逻辑混乱。 - 缺少默认值与回显逻辑:读取SharedPreferences时默认值传了空字符串,首次启动无配置时没有默认加载美元的规则;进入设置页时也没有读取已保存配置回显到Spinner上,用户看不到之前的选择。
修复方案
- 所有字符串内容判断全部改用
equals()方法,禁止用==比较字符串 - 清理SharedPreferences冗余键,只存储稳定的货币ID即可,名称、图标通过ID映射获取,避免重复存储数据不一致
- 把保存按钮的点击监听器从Spinner选中回调中移出来,仅在onCreate中绑定一次,点击时直接获取当前Spinner选中值保存
- 增加设置页回显逻辑,进入页面时自动选中已保存的货币项
- 配置默认值,首次启动默认加载美元
修复后代码
1. 改造Currency类,统一配置常量与映射方法
package com.myproject.offlinebudgettrackerappproject; import java.util.ArrayList; public class Currency { // 统一SharedPreferences常量,避免硬编码写错键名 public static final String PREF_NAME = "CURRENCY_SHARED"; public static final String KEY_CURRENCY_ID = "selected_currency_id"; public static final String DEFAULT_CURRENCY_ID = "0"; // 默认美元对应ID private static ArrayList<Currency> currencyArrayList = new ArrayList<>(); private String id; private String currency; public Currency(String id, String currency) { this.id = id; this.currency = currency; } public Currency() {} public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCurrency() { return currency; } public void setCurrency(String currency) { this.currency = currency; } public static void initCurrencies() { // 初始化前先清空列表,避免重复进入页面时货币项重复添加 currencyArrayList.clear(); Currency usd = new Currency("0", "US Dollars"); currencyArrayList.add(usd); Currency jpy = new Currency("1", "Japanese Yen"); currencyArrayList.add(jpy); Currency euro = new Currency("2", "Euro"); currencyArrayList.add(euro); } public int getCurrencyImage() { switch (getId()) { case "0": return R.drawable.ic_money; case "1": return R.drawable.ic_yen; case "2": return R.drawable.ic_euro; } return R.drawable.ic_money; } public static ArrayList<Currency> getCurrencyArrayList() { return currencyArrayList; } // 新增根据ID获取货币实例的方法,统一映射逻辑 public static Currency getCurrencyById(String id) { for (Currency currency : currencyArrayList) { if (currency.getId().equals(id)) { return currency; } } // 匹配不到返回默认美元 return currencyArrayList.get(0); } }
2. 修复BudgetTrackerSettingsActivity.java
package com.myproject.offlinebudgettrackerappproject; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.widget.Button; import android.widget.Spinner; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.myproject.offlinebudgettrackerappproject.adapter.CurrencySpinnerAdapter; public class BudgetTrackerSettingsActivity extends AppCompatActivity { private Spinner spinner; private Button currencyBtn; private SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_budget_tracker_settings); Currency.initCurrencies(); spinner = findViewById(R.id.currency_spinner); currencyBtn = findViewById(R.id.currency_btn); sharedPreferences = getSharedPreferences(Currency.PREF_NAME, MODE_PRIVATE); // 初始化Spinner适配器 CurrencySpinnerAdapter currencySpinnerAdapter = new CurrencySpinnerAdapter(this, R.layout.currency_spinner_adopter, Currency.getCurrencyArrayList()); spinner.setAdapter(currencySpinnerAdapter); // 回显已保存的货币选项 String savedCurrencyId = sharedPreferences.getString(Currency.KEY_CURRENCY_ID, Currency.DEFAULT_CURRENCY_ID); for (int i = 0; i < Currency.getCurrencyArrayList().size(); i++) { if (Currency.getCurrencyArrayList().get(i).getId().equals(savedCurrencyId)) { spinner.setSelection(i); break; } } // 保存按钮点击事件仅绑定一次 currencyBtn.setOnClickListener(view -> { Currency selectedCurrency = (Currency) spinner.getSelectedItem(); SharedPreferences.Editor editor = sharedPreferences.edit(); // 仅保存货币ID即可,不需要冗余存储名称 editor.putString(Currency.KEY_CURRENCY_ID, selectedCurrency.getId()); editor.apply(); // 异步写入不阻塞主线程,持久化效果和commit一致 Toast.makeText(BudgetTrackerSettingsActivity.this, "Currency Saved", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(BudgetTrackerSettingsActivity.this, MainActivity.class); startActivity(intent); finish(); }); } }
3. 修复HomeFragment.java读取逻辑
import android.content.Context; import android.content.SharedPreferences; // 读取保存的货币配置 SharedPreferences sharedPreferences = requireActivity().getSharedPreferences(Currency.PREF_NAME, Context.MODE_PRIVATE); String savedCurrencyId = sharedPreferences.getString(Currency.KEY_CURRENCY_ID, Currency.DEFAULT_CURRENCY_ID); Currency currentCurrency = Currency.getCurrencyById(savedCurrencyId); // 直接通过货币对象设置文本和图标,不需要写冗余的if-else判断 currentCurrencyTv.setText(currentCurrency.getCurrency()); currentCurrencyTv.setCompoundDrawablesWithIntrinsicBounds(currentCurrency.getCurrencyImage(), 0, 0, 0);
额外优化说明
- 后续新增货币类型时,只需要在
Currency.initCurrencies()方法中添加新的货币实例、配置对应图标即可,不需要修改保存、读取的业务逻辑,扩展性更强 - 所有配置键名都统一定义为常量,避免硬编码导致的键名写错、值覆盖问题
- 去掉了冗余的if-else分支,代码量减少70%,逻辑更清晰不容易出bug
内容的提问来源于stack exchange,提问作者AndroidEnthusiast
相关产品推荐
相关产品推荐

