Per-app language preferences是Android 13开始提供的一项系统级能力,它把语言设置从全局系统属性中拆解出来,让每个应用可以独立保存自己的显示语言。用户在系统设置中进入应用详情页的语言选项后,就可以单独为某个应用选择语言,例如系统语言保持简体中文,但让某个阅读类应用始终使用英文界面。对于开发者来说,这意味着应用不再必须依赖修改全局语言或重写attachBaseContext来实现语言切换,系统已经提供了标准的入口和持久化方案。

一、Per-app language preferences的工作机制
在Android 13之前,应用语言通常跟随系统语言。如果用户设置系统语言为英文,所有支持英文的应用都会用英文显示;如果把系统切回中文,应用也随之回到中文。开发者虽然可以在运行时通过重写attachBaseContext来修改Context的语言,但这种方式只对应用自身生效,用户在系统设置中看不到单独的语言选项,也容易出现配置不一致的问题。
Per-app language preferences把语言属性从单纯的系统级配置中拆解出来,变成每个应用可以独立维护的状态。系统会为每个应用保存一份LocaleList,并与应用本身的APK资源关联。用户在系统设置的应用详情页进入语言选项后,系统读取该应用声明的localeConfig语言列表,并将其选择结果持久化。当用户修改应用语言时,系统会重新创建该应用的任务栈,Activity经历销毁与重建,从而加载对应语言的资源。
这个机制的核心价值是用户无需为了某一个应用去修改整个系统的语言,也避免应用自行实现语言切换时与系统设置脱节。对于多语言用户或需要频繁切换语言的人群来说,这比以前的全局切换更加灵活。开发者需要做的是声明支持哪些语言,并通过系统API在应用内提供切换入口。
二、在清单文件中声明应用支持的语言
要让系统设置中显示应用的语言选项,首先需要创建一份语言配置文件。该文件通常放在res/xml目录下,根节点为<locale-config>,内部通过<locale>标签列出应用希望支持的语言。系统会根据这份列表生成可选项,并且只会加载列表中声明的语言资源。下面是一个包含简体中文、英文和日文的配置示例。
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="zh-CN"/>
<locale android:name="en-US"/>
<locale android:name="ja-JP"/>
</locale-config>
创建好语言配置文件后,需要在AndroidManifest.xml的<application>标签中通过android:localeConfig属性引用它。这个属性只有Android 13及以上的系统才会识别,低版本系统会直接忽略,因此不会影响安装。配置方式如下。
<application
android:name=".MyApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:localeConfig="@xml/locales_config">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
需要注意的是,如果没有在localeConfig中声明某个语言,即使用户的设备语言与该语言匹配,应用也不会主动加载该语言的资源。因此开发者应当确保列表中包含所有已经完成本地化的语言。同时,如果应用需要根据语言加载不同的布局或图片资源,也要为这些语言准备对应的资源目录,例如values-zh-rCN、values-en-rUS以及values-ja-rJP。
三、使用LocaleManager读取和设置应用语言
在应用内部,Android 13提供了android.app.LocaleManager来读取和修改应用语言。通过Context的getSystemService方法可以获取LocaleManager实例,然后调用getApplicationLocales或setApplicationLocales即可。下面的代码演示了如何获取当前应用语言以及如何切换为指定语言。
import android.app.LocaleManager
import android.content.Context
import android.os.Build
import android.os.LocaleList
import android.annotation.SuppressLint
class AppLanguageHelper(private val context: Context) {
@SuppressLint("NewApi")
fun getCurrentLanguageTag(): String {
val localeManager = context.getSystemService(LocaleManager::class.java)
val locales = localeManager.applicationLocales
return if (locales.isEmpty) {
"跟随系统"
} else {
locales[0].toLanguageTag()
}
}
@SuppressLint("NewApi")
fun setAppLanguage(languageTag: String) {
val localeManager = context.getSystemService(LocaleManager::class.java)
localeManager.applicationLocales = LocaleList.forLanguageTags(languageTag)
}
}
调用setAppLanguage后,系统会立即开始重建应用的任务栈。所有处于返回栈中的Activity都会被销毁并重新创建,因此界面上可能出现短暂的闪烁。如果应用没有做好状态保存,用户填写的表单、滚动位置或其他临时数据可能会丢失。开发者应当在Activity的onSaveInstanceState中保存关键状态,在onCreate或onRestoreInstanceState中恢复。
对于低版本设备,AndroidX提供了兼容方案。从AppCompat 1.6.0开始,AppCompatDelegate支持setApplicationLocales和getApplicationLocales方法。这些方法在Android 13及以上会委托给系统LocaleManager,在低版本上则使用AppCompat内部机制来模拟类似行为。示例代码如下。
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
fun setAppLanguageCompat(languageTag: String) {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.forLanguageTags(languageTag)
)
}
fun getAppLanguageCompat(): String {
val locales = AppCompatDelegate.getApplicationLocales()
return if (locales.isEmpty) {
"跟随系统"
} else {
locales[0].toLanguageTag()
}
}
使用AndroidX方案时,低版本设备还需要在AndroidManifest.xml中声明一个服务,用来在应用进程被系统回收后自动恢复语言偏好。缺少这个服务可能导致应用语言设置无法持久化。声明方式如下。
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true"/>
</service>
四、切换语言后的生命周期处理与常见问题
应用语言切换会触发Activity重建,但这个过程并不等同于普通的配置变更。系统会先销毁当前任务,再重新创建Activity。onSaveInstanceState一定会在销毁前被调用,因此如果没有保存状态,文本输入框中的内容、RecyclerView的滚动位置、Fragment的保存状态都可能丢失。为了降低影响,建议把重要状态放入ViewModel,并利用SavedStateHandle进行保存,这样即使Activity重建也能快速恢复。
另一个常见问题是资源加载不完整。如果应用在res/values目录下只提供了默认英文资源,但在localeConfig中声明了中文,用户选择中文后系统会加载中文字符串。如果某个字符串只在默认英文资源中存在,系统会回退到默认资源,这是正常的。但如果应用在代码中通过硬编码字符串展示内容,这些内容不会被翻译。开发者应确保所有用户可见文本都放在资源文件中,通过R.string引用。
还需要注意,部分开发者习惯在attachBaseContext中修改Locale,这与Android 13的Per-app language preferences机制可能产生冲突。例如在低版本上使用自定义语言切换逻辑后,系统设置中的语言选项不会与应用内自定义语言同步。建议在Android 13及以上系统统一使用LocaleManager,在低版本使用AndroidX兼容方案,尽量避免同时维护两套语言逻辑。
测试时可以利用adb命令模拟系统设置的应用语言变更。例如通过shell命令为某个包设置语言,能够快速验证Activity重建和资源加载是否正常。不过不同设备的系统设置入口名称可能略有差异,测试时应当以实际设备为准。总体而言,Per-app language preferences为应用语言切换提供了标准化支持,开发者只需完成清单配置和必要的状态保护,就能为用户带来更灵活的多语言体验。
应用内语言偏好LocaleManagerAndroid修改时间:2026-08-22 16:04:23