You need to enable JavaScript to run this app. Android应用共享常量最佳实践:适配View/ViewModel/XML/SharedPreferences
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 23:54:02