Android应用共享常量最佳实践:适配View/ViewModel/XML/SharedPreferences
Android全链路共享常量统一管理最佳实践
核心设计思路:实现代码端常量、XML资源、SharedPreferences键值三者同源,无需重复定义,同时规避ViewModel的Context依赖问题。
方案1:顶层常量 + 资源引用同步(轻量项目首选)
步骤1:创建全局常量文件
新建Constants.kt统一管理所有公共常量,无需依赖Context即可直接调用:
object AppConstants { // SharedPreferences 键统一管理 object SPKeys { const val ASPECT_SORT_ORDER = "aspect.sort_order" } // 排序选项值统一管理 object SortOrder { const val BY_LABEL = "by_label" const val BY_LABEL_DESC = "by_label_desc" const val BY_CREATED = "by_created" const val BY_CREATED_DESC = "by_created_desc" } }
步骤2:XML资源同步引用
在res/values/keys.xml(标记不可翻译)中存放和常量值完全一致的字符串资源,用于XML文件引用:
<resources xmlns:tools="http://schemas.android.com/tools"> <string name="sp_key_aspect_sort_order" translatable="false">aspect.sort_order</string> <string name="sort_by_label" translatable="false">by_label</string> <string name="sort_by_label_desc" translatable="false">by_label_desc</string> <string name="sort_by_created" translatable="false">by_created</string> <string name="sort_by_created_desc" translatable="false">by_created_desc</string> <string-array name="preferences_aspect_sort_order_values"> <item>@string/sort_by_label</item> <item>@string/sort_by_label_desc</item> <item>@string/sort_by_created</item> <item>@string/sort_by_created_desc</item> </string-array> </resources>
Preference配置文件直接引用资源即可:
<ListPreference app:defaultValue="@string/sort_by_label" app:entries="@array/preferences_aspect_sort_order_entries" app:entryValues="@array/preferences_aspect_sort_order_values" app:key="@string/sp_key_aspect_sort_order" app:title="@string/preferences_aspect_sort_order" app:useSimpleSummaryProvider="true" />
步骤3:业务代码直接调用常量
完全消除硬编码字符串:
// 读取SP val preferencesSort = sharedPreferences.getString(AppConstants.SPKeys.ASPECT_SORT_ORDER, AppConstants.SortOrder.BY_LABEL) // 逻辑判断 when(preferencesSort){ AppConstants.SortOrder.BY_LABEL -> sortByLabel() AppConstants.SortOrder.BY_LABEL_DESC -> sortByLabelDesc() AppConstants.SortOrder.BY_CREATED -> sortByCreated() AppConstants.SortOrder.BY_CREATED_DESC -> sortByCreatedDesc() else -> sortByLabel() }
方案2:枚举类 + 类型校验(中大型项目首选,类型安全)
如果需要更强的类型约束,避免字符串传参错误,可改用枚举类管理选项值:
enum class SortOrder(val value: String) { BY_LABEL("by_label"), BY_LABEL_DESC("by_label_desc"), BY_CREATED("by_created"), BY_CREATED_DESC("by_created_desc"); companion object { // 自动转换SP读取的字符串为枚举,处理异常兜底 fun fromValue(value: String?): SortOrder = values().find { it.value == value } ?: BY_LABEL } }
业务代码直接使用枚举,完全避免字符串拼写错误:
// 读取后直接转为枚举 val sortOrder = SortOrder.fromValue(sharedPreferences.getString(AppConstants.SPKeys.ASPECT_SORT_ORDER, null)) // 逻辑判断 when(sortOrder) { SortOrder.BY_LABEL -> sortByLabel() SortOrder.BY_LABEL_DESC -> sortByLabelDesc() SortOrder.BY_CREATED -> sortByCreated() SortOrder.BY_CREATED_DESC -> sortByCreatedDesc() }
一致性校验
新增单元测试确保代码常量和XML资源值完全一致:
@Test fun `check sort order constants match xml values`() { val context = ApplicationProvider.getApplicationContext<Context>() val xmlValues = context.resources.getStringArray(R.array.preferences_aspect_sort_order_values) val enumValues = SortOrder.values().map { it.value } assertArrayEquals(xmlValues, enumValues.toTypedArray()) }
额外优化:规避ViewModel Context依赖
将SP读写逻辑封装到仓库层,通过依赖注入注入到ViewModel,完全不需要在ViewModel中接触Context:
class SettingsRepository @Inject constructor(@ApplicationContext private val context: Context) { private val sp = PreferenceManager.getDefaultSharedPreferences(context) fun getSortOrder(): SortOrder { return SortOrder.fromValue(sp.getString(AppConstants.SPKeys.ASPECT_SORT_ORDER, null)) } fun saveSortOrder(order: SortOrder) { sp.edit().putString(AppConstants.SPKeys.ASPECT_SORT_ORDER, order.value).apply() } }
ViewModel中直接注入仓库使用即可:
class MainViewModel @Inject constructor(private val settingsRepository: SettingsRepository) : ViewModel() { val sortOrder = settingsRepository.getSortOrder() }
内容的提问来源于stack exchange,提问作者Gattaccio7
相关产品推荐
相关产品推荐

