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

Android8+后台接收ACTION_LOCALE_CHANGED时Activity资源未更新

action:sendBroadcast ACTION_LOCALE_CHANGED

我在Activity的onCreate()生命周期方法中注册了针对ACTION_LOCALE_CHANGED的广播接收器,当接收器接收到对应广播时会调用localeChanged()方法。我尝试通过以下两个API获取变更后的语言区域配置:

  • A) getApplicationContext().getResources().getConfiguration()
  • B) this.getResources().getConfiguration()

测试发现,通过API A可以正常获取到正确的最新语言区域配置,但通过API B始终无法获取更新后的正确配置,一直返回变更前的旧语言区域值。

问题复现步骤:

  1. 打开测试应用,此时应用语言区域为"en"(系统默认语言区域也为"en")
  2. 按下Home键,将应用切至后台运行
  3. 将系统语言区域从"en"修改为"ja"
  4. 系统全局界面已全部切换为日语"ja"
  5. 重新打开测试应用,将应用从后台切回前台
  6. 应用内语言未同步更新,仍显示变更前的旧语言内容

上述localeChanged()方法是应用处于后台状态时,接收到ACTION_LOCALE_CHANGED广播后触发调用的。
在Android 6、7版本中,调用this.getResources().getConfiguration()可正常获取正确的资源与语言区域配置,但Android 8及以上版本在后台接收ACTION_LOCALE_CHANGED广播时会出现上述语言不更新的问题,在Android官方模拟器上也可稳定复现该问题。

onConfigurationChanged()

上述场景下,通过onConfigurationChanged()回调可以正常获取到更新后的正确语言区域配置。
虽然通过onConfigurationChanged()可以拿到最新的正确语言配置,但需要明确:为何通过ACTION_LOCALE_CHANGED广播触发逻辑时,调用this.getResources().getConfiguration() API无法获取到更新后的语言区域配置,Android 7.1与Android 8版本之间是否存在相关API差异?

相关源码

onCreate()中注册广播的代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.i(TAG,"onCreate");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    IntentFilter testLocaleChangedFilter = new IntentFilter();
    testLocaleChangedFilter.addAction(Intent.ACTION_LOCALE_CHANGED);

    getApplicationContext().registerReceiver(new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
          localeChanged();
        }
    }, testLocaleChangedFilter);
}

广播接收后调用的localeChanged()方法、以及onConfigurationChanged()回调代码:

private void localeChanged() {

   Configuration config = getApplicationContext().getResources().getConfiguration();
   Log.i(TAG, "localeChanged - getApplicationContext().getResources().getConfiguration():" + config);
  
   Configuration config2 = this.getResources().getConfiguration();
   Log.i(TAG, "localeChanged - this.getResources().getConfiguration():" + config2.locale);

   ((TextView)findViewById(R.id.text_language)).setText(R.string.language_text);
  
   Log.i(TAG,"getResources().getString(R.string.language_text):" + getResources().getString(R.string.language_text));
}

@Override
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
    Log.i(TAG, "onConfigurationChanged");
    super.onConfigurationChanged(newConfig);

    String locale = Locale.getDefault().toString();
    Log.i(TAG, "onConfigurationChanged(Locale):" + locale);

    Configuration config2 = this.getResources().getConfiguration();
    Log.i(TAG, "onConfigurationChanged-this.getResources().getConfiguration():" + config2.locale);
}

问题解答

这个现象是Android 8.0(API 26)对组件资源更新逻辑做了后台优化调整导致的,核心逻辑如下:

两类Context的资源实例差异

  • getApplicationContext()返回的是全局Application级Context,它持有的Resources实例是进程全局共享的,系统在发送ACTION_LOCALE_CHANGED广播前,就已经完成了这个全局实例的Configuration更新,任何时候通过它读取配置都能拿到最新值。
  • Activity持有的Context是ContextThemeWrapper包装的独立实例,绑定了Activity专属的主题与窗口资源,Resources是单独缓存的,不会和全局Application的Resources自动同步。

跨版本行为差异根源

  • Android 7.1及更低版本:系统派发ACTION_LOCALE_CHANGED广播前,会主动遍历进程内所有存活组件(包括后台状态的Activity),统一更新所有组件持有的Resources缓存配置,所以广播回调里调用Activity的getResources()能直接拿到最新配置。
  • Android 8.0及更高版本:系统收紧了后台组件的资源更新逻辑:仅当组件处于前台活跃状态时,才会同步更新它的Resources缓存;处于后台onStop()状态的Activity,不会在广播派发阶段触发资源更新。
    应用切到后台后,目标Activity已经进入停止状态,此时系统触发语言变更,只会更新全局Application的Resources,不会主动刷新后台Activity的缓存资源,所以广播回调里调用Activity的getResources()拿到的是变更前的旧值。
    等应用切回前台,系统才会给该Activity派发onConfigurationChanged()回调(未配置configChanges属性的话会直接重建Activity),这一步才会同步更新Activity绑定的Resources配置,所以在onConfigurationChanged()回调里能读取到正确的最新语言配置。

适配方案

  • 读取全局系统配置(包括语言区域、屏幕参数等)时,统一使用Application Context的Resources实例,不要依赖后台Activity Context的缓存资源。
  • 语言变更后的UI刷新逻辑,不要在后台广播回调里直接执行,放到onConfigurationChanged()回调、或者Activity回到前台的onStart()生命周期里处理即可,这两个时机点Activity的Resources已经完成更新,能正确加载对应语言的字符串资源。
  • 不建议在广播回调里手动给Activity调用applyOverrideConfiguration()或者手动创建Resources实例强制更新,这类操作容易和系统后续的配置派发逻辑冲突,引发资源显示错乱、内存泄漏等问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:45:34