【问题标题】:Change Locale not work after migrate to Androidx迁移到 Androidx 后更改区域设置不起作用
【发布时间】:2019-08-11 10:42:41
【问题描述】:

我有一个支持多语言的旧项目。我想升级支持库和目标平台,在迁移到 Androidx 之前一切正常,但现在更改语言不起作用!

我使用此代码更改 App 的默认语言环境

private static Context updateResources(Context context, String language)
{
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);

    return context.createConfigurationContext(configuration);
}

并通过像这样覆盖attachBaseContext 在每个活动上调用此方法:

@Override
protected void attachBaseContext(Context newBase)
{
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    String language = preferences.getString(SELECTED_LANGUAGE, "fa");
    super.attachBaseContext(updateResources(newBase, language));
}

我尝试了其他方法来获取字符串,我注意到 ‍‍‍‍getActivity().getBaseContext().getString 有效,getActivity().getString 无效。即使以下代码也不起作用,并且始终在默认资源 string.xml 中显示app_name vlaue。

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/app_name"/>

我在https://github.com/Freydoonk/LanguageTest分享一个示例代码

还有getActivity()..getResources().getIdentifier 不工作,总是返回0!

【问题讨论】:

  • 我认为如果您提供示例应用程序,这类问题会更​​容易解决。
  • 您是否在应用语言更改后重新创建活动?
  • @mustafiz012 如果我在 attachBaseContext 中调用 recareate 进行循环调用并...
  • @IbrahimAli 我在github.com/Freydoonk/LanguageTest分享了一个示例代码
  • 有趣的是,设置 android:configChanges="uiMode" 解决了这个问题,但是,当我们在明暗主题之间切换时,自然而然地会出现颜色伪影......

标签: android android-activity android-support-library androidx


【解决方案1】:

现在语言不会随着这些库而改变: androidx.appcompat:appcompat:1.1.0, androidx.appcompat:appcompat:1.2.0

这个问题只在这个库中解决了: androidx.appcompat:appcompat:1.3.0-rc01

【讨论】:

  • 你好,在生产级版本中使用 1.3.0-rc01 版本而不是 1.2.0 版本好吗?
  • 是的,很好。否则,1.2.0 根本不工作。就我而言,Application 上下文存在问题,但 Activity 上下文一切正常。
【解决方案2】:

解决方案:

在 App 级 Gradle 中,我在 android 部门中包含了以下代码,

bundle {
    language {
        // Specifies that the app bundle should not support
        // configuration APKs for language resources. These
        // resources are instead packaged with each base and
        // dynamic feature APK.
        enableSplit = false
    }
}

https://medium.com/dwarsoft/how-to-provide-languages-dynamically-using-app-bundle-567d2ec32be6

【讨论】:

    【解决方案3】:

    2020 年 8 月 21 日更新:

    AppCompat 1.2.0 终于发布了。如果您根本没有使用 ContextWrapperContextThemeWrapper,则应该没有其他事情可做,您应该可以删除 1.1.0 中的任何解决方法!

    如果您在attachBaseContext 中使用ContextWrapperContextThemeWrapper,语言环境更改将会中断,因为当您将包装的上下文传递给super 时,

    1. 1.2.0 AppCompatActivity 进行内部调用,将您的ContextWrapper 包装在另一个ContextThemeWrapper 中,
    2. 或者如果您使用 ContextThemeWrapper,将其配置覆盖为空白,类似于 1.1.0 中发生的情况。

    但解决方案总是一样的。对于情况 2,我尝试了多种其他解决方案,但正如 @Kreiri 在 cmets 中指出的那样(感谢您的调查帮助!),AppCompatDelegateImpl 总是最终剥离了语言环境。最大的障碍是,与 1.1.0 不同,applyOverrideConfiguration 是在您的基本上下文而不是您的主机活动中调用的,因此您不能像在 1.1.0 中那样在活动中覆盖该方法并修复语言环境.我知道的唯一可行的解​​决方案是通过覆盖getDelegate() 来反转包装,以确保你的包装和/或语言环境覆盖在最后。首先,添加下面的类:

    Kotlin 示例(请注意,该类必须位于 androidx.appcompat.app 包内,因为唯一现有的 AppCompatDelegate 构造函数是包私有的)

    package androidx.appcompat.app
    
    import android.content.Context
    import android.content.res.Configuration
    import android.os.Bundle
    import android.util.AttributeSet
    import android.view.MenuInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.appcompat.view.ActionMode
    import androidx.appcompat.widget.Toolbar
    
    class BaseContextWrappingDelegate(private val superDelegate: AppCompatDelegate) : AppCompatDelegate() {
    
        override fun getSupportActionBar() = superDelegate.supportActionBar
    
        override fun setSupportActionBar(toolbar: Toolbar?) = superDelegate.setSupportActionBar(toolbar)
    
        override fun getMenuInflater(): MenuInflater? = superDelegate.menuInflater
    
        override fun onCreate(savedInstanceState: Bundle?) {
            superDelegate.onCreate(savedInstanceState)
            removeActivityDelegate(superDelegate)
            addActiveDelegate(this)
        }
    
        override fun onPostCreate(savedInstanceState: Bundle?) = superDelegate.onPostCreate(savedInstanceState)
    
        override fun onConfigurationChanged(newConfig: Configuration?) = superDelegate.onConfigurationChanged(newConfig)
    
        override fun onStart() = superDelegate.onStart()
    
        override fun onStop() = superDelegate.onStop()
    
        override fun onPostResume() = superDelegate.onPostResume()
    
        override fun setTheme(themeResId: Int) = superDelegate.setTheme(themeResId)
    
        override fun <T : View?> findViewById(id: Int) = superDelegate.findViewById<T>(id)
    
        override fun setContentView(v: View?) = superDelegate.setContentView(v)
    
        override fun setContentView(resId: Int) = superDelegate.setContentView(resId)
    
        override fun setContentView(v: View?, lp: ViewGroup.LayoutParams?) = superDelegate.setContentView(v, lp)
    
        override fun addContentView(v: View?, lp: ViewGroup.LayoutParams?) = superDelegate.addContentView(v, lp)
    
        override fun attachBaseContext2(context: Context) = wrap(superDelegate.attachBaseContext2(super.attachBaseContext2(context)))
    
        override fun setTitle(title: CharSequence?) = superDelegate.setTitle(title)
    
        override fun invalidateOptionsMenu() = superDelegate.invalidateOptionsMenu()
    
        override fun onDestroy() {
            superDelegate.onDestroy()
            removeActivityDelegate(this)
        }
    
        override fun getDrawerToggleDelegate() = superDelegate.drawerToggleDelegate
    
        override fun requestWindowFeature(featureId: Int) = superDelegate.requestWindowFeature(featureId)
    
        override fun hasWindowFeature(featureId: Int) = superDelegate.hasWindowFeature(featureId)
    
        override fun startSupportActionMode(callback: ActionMode.Callback) = superDelegate.startSupportActionMode(callback)
    
        override fun installViewFactory() = superDelegate.installViewFactory()
    
        override fun createView(parent: View?, name: String?, context: Context, attrs: AttributeSet): View? = superDelegate.createView(parent, name, context, attrs)
    
        override fun setHandleNativeActionModesEnabled(enabled: Boolean) {
            superDelegate.isHandleNativeActionModesEnabled = enabled
        }
    
        override fun isHandleNativeActionModesEnabled() = superDelegate.isHandleNativeActionModesEnabled
    
        override fun onSaveInstanceState(outState: Bundle?) = superDelegate.onSaveInstanceState(outState)
    
        override fun applyDayNight() = superDelegate.applyDayNight()
    
        override fun setLocalNightMode(mode: Int) {
            superDelegate.localNightMode = mode
        }
    
        override fun getLocalNightMode() = superDelegate.localNightMode
    
        private fun wrap(context: Context): Context {
            TODO("your wrapping implementation here")
        }
    }
    

    然后在我们的基础活动类中删除所有 1.1.0 解决方法并简单地添加以下内容:

    private var baseContextWrappingDelegate: AppCompatDelegate? = null
    
    override fun getDelegate() = baseContextWrappingDelegate ?: BaseContextWrappingDelegate(super.getDelegate()).apply {
        baseContextWrappingDelegate = this
    }
    

    根据您使用的ContextWrapper 实现,配置更改可能会破坏主题或区域设置更改。要解决此问题,请另外添加:

    override fun createConfigurationContext(overrideConfiguration: Configuration) : Context {
        val context = super.createConfigurationContext(overrideConfiguration)
        TODO("your wrapping implementation here")
    }
    

    你很好!您可以期待 Google 在 1.3.0 中再次打破这一点。我会去修复它……再见,太空牛仔!

    APPCOMPAT 1.1.0 的旧答案和解决方案:

    基本上,在后台发生的情况是,当您在 attachBaseContext 中正确设置了配置时,AppCompatDelegateImpl 然后会将配置覆盖为完全没有语言环境的全新配置

     final Configuration conf = new Configuration();
     conf.uiMode = newNightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
    
     try {
         ...
         ((android.view.ContextThemeWrapper) mHost).applyOverrideConfiguration(conf);
         handled = true;
     } catch (IllegalStateException e) {
         ...
     }
    

    In an unreleased commit by Chris Banes 这实际上已修复:新配置是基本上下文配置的深层副本。

    final Configuration conf = new Configuration(baseConfiguration);
    conf.uiMode = newNightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
    try {
        ...
        ((android.view.ContextThemeWrapper) mHost).applyOverrideConfiguration(conf);
        handled = true;
    } catch (IllegalStateException e) {
        ...
    }
    

    在此版本发布之前,可以手动执行完全相同的操作。要继续使用 1.1.0 版,请将其添加到您的 attachBaseContext 下方:

    Kotlin 解决方案

    override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
        if (overrideConfiguration != null) {
            val uiMode = overrideConfiguration.uiMode
            overrideConfiguration.setTo(baseContext.resources.configuration)
            overrideConfiguration.uiMode = uiMode
        }
        super.applyOverrideConfiguration(overrideConfiguration)
    }
    

    Java 解决方案

    @Override
    public void applyOverrideConfiguration(Configuration overrideConfiguration) {
        if (overrideConfiguration != null) {
            int uiMode = overrideConfiguration.uiMode;
            overrideConfiguration.setTo(getBaseContext().getResources().getConfiguration());
            overrideConfiguration.uiMode = uiMode;
        }
        super.applyOverrideConfiguration(overrideConfiguration);
    }
    

    这段代码的作用与Configuration(baseConfiguration) 在底层所做的完全一样,但是因为我们是在之后AppCompatDelegate 已经设置了正确的uiMode,所以我们必须确保在我们修复它之后将覆盖的uiMode 转移到它,这样我们就不会丢失暗/亮模式设置。

    请注意,仅当您未在清单中指定 configChanges="uiMode" 时,它才会自行起作用。如果你这样做了,那么还有另一个错误:在onConfigurationChanged 内部,newConfig.uiMode 不会由AppCompatDelegateImplonConfigurationChanged 设置。如果您将所有代码 AppCompatDelegateImpl 用于计算当前夜间模式复制到您的基本活动代码,然后在 super.onConfigurationChanged 调用之前覆盖它,也可以修复此问题。在 Kotlin 中它看起来像这样:

    private var activityHandlesUiMode = false
    private var activityHandlesUiModeChecked = false
    
    private val isActivityManifestHandlingUiMode: Boolean
        get() {
            if (!activityHandlesUiModeChecked) {
                val pm = packageManager ?: return false
                activityHandlesUiMode = try {
                    val info = pm.getActivityInfo(ComponentName(this, javaClass), 0)
                    info.configChanges and ActivityInfo.CONFIG_UI_MODE != 0
                } catch (e: PackageManager.NameNotFoundException) {
                    false
                }
            }
            activityHandlesUiModeChecked = true
            return activityHandlesUiMode
        }
    
    override fun onConfigurationChanged(newConfig: Configuration) {
        if (isActivityManifestHandlingUiMode) {
            val nightMode = if (delegate.localNightMode != AppCompatDelegate.MODE_NIGHT_UNSPECIFIED) 
                delegate.localNightMode
            else
                AppCompatDelegate.getDefaultNightMode()
            val configNightMode = when (nightMode) {
                AppCompatDelegate.MODE_NIGHT_YES -> Configuration.UI_MODE_NIGHT_YES
                AppCompatDelegate.MODE_NIGHT_NO -> Configuration.UI_MODE_NIGHT_NO
                else -> applicationContext.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
            }
            newConfig.uiMode = configNightMode or (newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv())
        }
        super.onConfigurationChanged(newConfig)
    }
    

    【讨论】:

    • 它非常适合我。谢谢!但是,我不明白重写“applyOverrideConfiguration”方法如何解决问题。你能解释一下吗?
    • @Burak 如果您检查 ContextThemeWrapper 的源代码,您应该能够看到传递给 super.applyOverrideConfiguration(overrideConfiguration) 的任何内容都被存储并稍后用于获取任何类型的资源。这就是谷歌实现日/夜主题的方式。基本资源配置没有正确的 uiMode 设置,因此 ContextThemeWrapper 覆盖 getResources() 以返回配置具有它的实例。
    • @phongvan 有什么问题?我已经使用了很长时间,并且从来没有遇到横向或纵向/横向切换的问题。可以肯定的是,如果您遇到任何与 1.1.0 版中的其他错误相关的故障,而不是我的解决方案,因为正如答案中所述,它直接来自 Google 的官方修复。
    • @TaiNguyen 你的 updateResource 方法是什么,它有什么作用?需要指出的是,如果您在 attachBaseContext 中使用 ContextWrappers,则需要进行更多代码更改才能使我的解决方案正常工作,因为 ContextWrappers 可能有自己的逻辑,例如存储陈旧的资源和配置实例。
    • 如果它可能对任何人有帮助,here 是基于使用 AppCompatActivity 活动和库版本 1.2.0 将此答案与 another one 结合的工作区域设置更改实现的完整差异.
    【解决方案4】:

    我正在使用“androidx.appcompat:appcompat:1.3.0-alpha01”,但我想它也适用于Version 1.2.0
    以下代码基于Android Code Search

    import android.content.Context
    import android.content.res.Configuration
    import android.os.Build
    import androidx.appcompat.app.AppCompatActivity
    import java.util.*
    
    open class MyBaseActivity :AppCompatActivity(){
    
        override fun attachBaseContext(newBase: Context?) {
            super.attachBaseContext(newBase)
            val config = Configuration()
            applyOverrideConfiguration(config)
        }
    
        override fun applyOverrideConfiguration(newConfig: Configuration) {
            super.applyOverrideConfiguration(updateConfigurationIfSupported(newConfig))
        }
    
        open fun updateConfigurationIfSupported(config: Configuration): Configuration? {
            // Configuration.getLocales is added after 24 and Configuration.locale is deprecated in 24
            if (Build.VERSION.SDK_INT >= 24) {
                if (!config.locales.isEmpty) {
                    return config
                }
            } else {
                if (config.locale != null) {
                    return config
                }
            }
            // Please Get your language code from some storage like shared preferences
            val languageCode = "fa"
            val locale = Locale(languageCode)
            if (locale != null) {
                // Configuration.setLocale is added after 17 and Configuration.locale is deprecated
                // after 24
                if (Build.VERSION.SDK_INT >= 17) {
                    config.setLocale(locale)
                } else {
                    config.locale = locale
                }
            }
            return config
        }
    }
    

    【讨论】:

    • 我认为这是解决我问题的最简单的答案,谢谢! @EhsanShadi 我将等待 1.3.0 更新到那时会发生什么,:)
    • 这个怎么样?创建新配置会覆盖所有预定义的配置并破坏 ui。
    • @dor506 您遇到了什么样的 UI 损坏?这似乎是唯一对我有用的解决方案 androidx.appcompat:appcompat:1.3.0-alpha03 但很高兴知道一些准备发布的警告。谢谢
    • @saintjab 看看 0101100101 最新更新(8 月 20 日),它在更新当前配置时确实有效(context.getResources().getConfiguration()),而不是在每个活动。
    【解决方案5】:

    试试这样的:

    public class MyActivity extends AppCompatActivity {
        public static final float CUSTOM_FONT_SCALE = 4.24f;
        public static final Locale CUSTOM_LOCALE = Locale.CANADA_FRENCH; // or whatever
    
        @Override
        protected void attachBaseContext(Context newBase) {
            super.attachBaseContext(useCustomConfig(newBase));
        }
    
        private Context useCustomConfig(Context context) {
            Locale.setDefault(CUSTOM_LOCALE);
            if (Build.VERSION.SDK_INT >= 17) {
                Configuration config = new Configuration();
                config.fontScale = CUSTOM_FONT_SCALE;
                config.setLocale(CUSTOM_LOCALE);
                return context.createConfigurationContext(config);
            } else {
                Resources res = context.getResources();
                Configuration config = new Configuration(res.getConfiguration());
                config.fontScale = CUSTOM_FONT_SCALE;
                config.locale = CUSTOM_LOCALE;
                res.updateConfiguration(config, res.getDisplayMetrics());
                return context;
            }
        }
    }   
    

    来源:issuetracker commentfirst sample linked from the issuetracker comment

    虽然以上对我来说工作正常,但second sample linked from the issuetracker comment 的另一个选项如下(我没有亲自尝试过):

    @RequiresApi(17)
    public class MyActivity extends AppCompatActivity {
        public static final float CUSTOM_FONT_SCALE = 4.24f;
        public static final Locale CUSTOM_LOCALE = Locale.CANADA_FRENCH; // or whatever
    
        @Override
        protected void attachBaseContext(Context newBase) {
            super.attachBaseContext(newBase);
    
            Configuration config = new Configuration();
            config.fontScale = CUSTOM_FONT_SCALE;
            applyOverrideConfiguration(config);
        }
    
        @Override
        public void applyOverrideConfiguration(Configuration newConfig) {
            super.applyOverrideConfiguration(updateConfigurationIfSupported(newConfig));
        }
    
        private Configuration updateConfigurationIfSupported(Configuration config) {
            if (Build.VERSION.SDK_INT >= 24) {
                if (!config.getLocales().isEmpty()) {
                    return config;
                }
            } else {
                if (config.locale != null) {
                    return config;
                }
            }
    
            Locale locale = CUSTOM_LOCALE;
            if (locale != null) {
                if (Build.VERSION.SDK_INT >= 17) {
                    config.setLocale(locale);
                } else {
                    config.locale = locale;
                }
            }
            return config;
        }
    }
    

    【讨论】:

    • config.setLocale(locale); 应在 Android N (24) 或更高版本上。
    【解决方案6】:

    迟到的答案,但我认为可能会有所帮助。从 androidx.appcompat:appcompat:1.2.0-beta01 开始,0101100101 覆盖 applyOverrideConfiguration 的解决方案不再适用于我。相反,在随后覆盖的attacheBaseContext 中,您必须调用applyOverrideConfiguration() 而不覆盖它

    override fun attachBaseContext(newBase: Context) {
        val newContext = LocaleHelper.getUpdatedContext(newBase)
        super.attachBaseContext(newContext)
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1){
            applyOverrideConfiguration(newContext.resources.configuration)
        }
    }
    

    很遗憾,他的解决方案仅适用于 1.1.0。根据我的研究,这应该已经正式修复。奇怪的是,这个错误还在这里。我知道我使用的是测试版,但对于想要使用最新版本的人来说,这个解决方案对我来说是有效的。 在模拟器 api 级别 21-25 上测试。超过那个 api 级别,您不必担心。

    【讨论】:

    • 这是唯一适用于 androidx.appcompat...1.2.0 的解决方案,否则某些手机(在我的情况下是三星 s5)中没有发生区域设置更改谢谢!
    【解决方案7】:

    androidx.appcompat:appcompat:1.1.0 错误也可以通过在Activity.applyOverrideConfiguration() 中调用getResources() 来解决

    @Override public void
    applyOverrideConfiguration(Configuration cfgOverride)
    {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
          Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        // add this to fix androidx.appcompat:appcompat 1.1.0 bug
        // which happens on Android 6.x ~ 7.x
        getResources();
      }
    
      super.applyOverrideConfiguration(cfgOverride);
    }
    

    【讨论】:

      【解决方案8】:

      @0101100101 的回答对我有用。

      只有我用过的

      @Override
      public void applyOverrideConfiguration(Configuration overrideConfiguration)
      {
        if (overrideConfiguration != null) {
          int uiMode = overrideConfiguration.uiMode;
          overrideConfiguration.setTo(getResources().getConfiguration());
          overrideConfiguration.uiMode = uiMode;
        }
        super.applyOverrideConfiguration(overrideConfiguration);
      }
      

      所以只有getResources() 而不是getBaseContext().getResources()

      在我的例子中,我使用重写的 getResources() 扩展了 ContextWrapper。 但是在调用 applyOverrideConfiguration 之后,我无法访问我的自定义 getResources。我得到的是标准的。

      如果我使用上面的代码一切正常。

      【讨论】:

        【解决方案9】:

        最后,我在我的应用程序中找到了问题。将项目迁移到 Androidx 时,我的项目的依赖项更改如下:

        dependencies {
            implementation fileTree(include: ['*.jar'], dir: 'libs')
            implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
            implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
            implementation 'com.google.android.material:material:1.1.0-alpha04'
            androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha02'
        } 
        

        正如所见,androidx.appcompat:appcompat 的版本是1.1.0-alpha03,当我将其更改为最新的稳定版本1.0.2 时,我的问题已解决并且更改语言正常工作。

        我在Maven Repository 中找到了appcompat 库的最新稳定版本。我还将其他库更改为最新的稳定版本。

        现在我的应用依赖部分如下所示:

        dependencies {
            implementation fileTree(include: ['*.jar'], dir: 'libs')
            implementation 'androidx.appcompat:appcompat:1.0.2'
            implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
            implementation 'com.google.android.material:material:1.0.0'
            androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
        }
        

        【讨论】:

        • 我遇到了类似的问题。我已经为appcompat 提供了稳定的1.0.2,但我的问题出在设计支持库或com.google.android.material:material:1.1.0-alpha06 中。所以当我切换到马厩1.0.0时,它是固定的。
        【解决方案10】:

        与夜间模式相关的新应用兼容库中存在一个问题,导致覆盖 android 21 到 25 上的配置。 这可以通过在调用此公共函数时应用您的配置来解决:

        public void applyOverrideConfiguration(配置覆盖配置

        对我来说,这个小技巧通过将设置从被覆盖的配置复制到我的配置而奏效,但你可以做任何你想做的事情。最好将您的语言逻辑重新应用到新配置中以最大程度地减少错误

        @Override
        public void applyOverrideConfiguration(Configuration overrideConfiguration) {
            if (Build.VERSION.SDK_INT >= 21&& Build.VERSION.SDK_INT <= 25) {
                //Use you logic to update overrideConfiguration locale
                Locale locale = getLocale()//your own implementation here;
                overrideConfiguration.setLocale(locale);
            }
            super.applyOverrideConfiguration(overrideConfiguration);
        }
        

        【讨论】:

        • 此代码更改导致某些设备上的多个位置崩溃Attempt to invoke virtual method 'java.lang.String java.util.Locale.toString()' on a null object reference android.widget.Editor$TextActionModeCallback.populateMenuWithItemsExt。最好降级或遵循@0101100101 的回答..
        • getLocale 和 setLocale 应该在 Android N/24 or above
        【解决方案11】:

        androidx.appcompat:appcompat:1.1.0 上有同样的错误。切换到androidx.appcompat:appcompat:1.1.0-rc01,现在在Android 5-6. 上更改语言

        【讨论】:

          【解决方案12】:

          最后我得到了定位解决方案,在我的情况下,实际上问题是bundle apk,因为它拆分了定位文件。默认情况下,bundle apk 中将生成所有拆分。但在build.gradle 文件的android 块中,您可以声明将生成哪些拆分。

          bundle {
                      language {
                          // Specifies that the app bundle should not support
                          // configuration APKs for language resources. These
                          // resources are instead packaged with each base and
                          // dynamic feature APK.
                          enableSplit = false
                      }
                  }
          

          将此代码添加到 build.gradle 文件的 android 块后,我的问题得到解决。

          【讨论】:

          • 我遇到了同样的问题。当我过去在 Play 商店发布之前进行检查时,一切正常,而在发布语言环境更改后,一切都不起作用。我应用了这个解决方案,现在可以完美运行。谢谢
          • 我遇到了同样的问题。每当我安装调试版本时,它都在工作,但是当我发布捆绑包时出现问题并尝试了很多解决方案,但这是唯一有效的解决方案。谢谢。
          • 这个!这很有意义。其中一部测试手机从未显示应用程序中选择的语言,我们想知道为什么它只在从 Google Play 下载时才会出现。我通过添加系统语言->清除数据->重新启动应用程序来验证它是否正常工作。谢谢!
          【解决方案13】:

          现在有一个更新的版本也可以使用:

          implementation 'androidx.appcompat:appcompat:1.1.0-alpha04'
          

          正如@Fred 提到的appcompat:1.1.0-alpha03 有一个小故障,尽管他们的release versions log 上没有提到它

          【讨论】:

          • 我测试androidx.appcompat:appcompat:1.1.0-alpha04,还是有这个问题。
          • 因为我的生产应用程序工作得很好,我为每个活动在attachBaseContext(Context newBase) 中使用ContextWrapper 的自定义实现
          【解决方案14】:

          1.您可以在 attachBaseContext()

          中使用的方法
          private void setLanguage(Context mContext, String localeName) {
                  Locale myLocale = new Locale(localeName);
                  Resources res = mContext.getResources();
                  DisplayMetrics dm = res.getDisplayMetrics();
                  Configuration conf = res.getConfiguration();
                  conf.locale = myLocale;
                  res.updateConfiguration(conf, dm);
              }
          

          2。在活动中覆盖

          @Override
          protected void attachBaseContext(Context newBase) {
              setLanguage(newBase, "your language");
              super.attachBaseContext(newBase);
          }
          

          注意:在我重新创建活动后,这对我来说工作正常

          【讨论】:

          • 你在哪里调用'recreate();`
          • 假设,您使用按钮单击来更改语言。在这种情况下,当您单击按钮时,将您的语言放入共享首选项并重新创建您的活动。必要时从共享首选项中获取语言字符串。如果您需要更多详细信息,我将分享代码示例。
          • 我这样做了,我将所选语言保留在共享首选项中并重新创建应用程序,我从共享首选项中获取所选语言并传递给 attachBaseContext 中的 setLanguage(newBase, myPpersistedLanguage); 但这不起作用。我在我的问题的示例代码中编辑了一个完整的attachBaseContext 以显示这一点。
          • 我认为您的 strings.xml 文件未按要求配置。如果你告诉我,你有替代的 strings.xml 文件吗?例如:strings.xml、strings.xml(fa)
          • 我在我的项目中添加了我的资源截图
          猜你喜欢
          • 1970-01-01
          • 2020-03-02
          • 1970-01-01
          • 2019-05-08
          • 2020-07-12
          • 2019-04-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多