迁移到Androidx后更改语言环境不起作用

Fre*_*red 21 android android-activity android-support-library androidx

我有一个支持多种语言的旧项目。我想升级支持库和目标平台,在迁移到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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/app_name"/>
Run Code Online (Sandbox Code Playgroud)

我在https://github.com/Freydoonk/LanguageTest中共享示例代码

getActivity()..getResources().getIdentifier行不通,总是返回0!

010*_*101 36

基本上,在后台发生的事情是,当您在中正确设置了配置后attachBaseContextAppCompatDelegateImpl然后它将覆盖该配置,并将其覆盖为完全没有区域设置的全新配置

 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) {
     ...
 }
Run Code Online (Sandbox Code Playgroud)

在最新(尚未发布)的代码中,此问题实际上已得到修复:新配置是基本上下文配置的深层副本。

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) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

在此版本发布之前,可以手动执行完全相同的操作。要继续使用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)
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

此代码不正是相同的Configuration(baseConfiguration)引擎盖下做,而是因为我们正在做这之后AppCompatDelegate已设置正确的uiMode,我们必须确保采取覆盖uiMode到我们修复它之后,所以我们不会失去黑暗/灯光模式设置。

  • 如果它可能对任何人有帮助,[此处](https://github.com/CNugteren/NLWeer/pull/20/files) 是基于将此答案与[另一个答案]相结合的工作区域设置更改实现的完整差异one](/sf/answers/3964137341/) 使用 AppCompatActivity 活动和库版本 1.2.0。 (2认同)

Jac*_*bos 13

与夜间模式相关的新应用程序兼容库中存在一个问题,该问题导致覆盖 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);
}
Run Code Online (Sandbox Code Playgroud)


Ehs*_*adi 9

我正在使用 "androidx.appcompat:appcompat:1.3.0-alpha01" 但我想它也适用于Version 1.2.0
以下代码基于Android 代码搜索

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
    }
}
Run Code Online (Sandbox Code Playgroud)


Fre*_*red 8

最后,我在我的应用程序中发现了问题。将项目迁移到我的项目的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'
} 
Run Code Online (Sandbox Code Playgroud)

可以看到,版本androidx.appcompat:appcompat1.1.0-alpha03当我将其更改为最新的稳定版本时1.0.2,我的问题已解决并且更改语言正常工作。

我在Maven存储库中找到了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'
}
Run Code Online (Sandbox Code Playgroud)


Cod*_*ave 8

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

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Man*_*hir 5

最后我得到了 locate 的解决方案,在我的情况下,实际问题是bundle apk 因为它拆分了 locate 文件。在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
            }
        }
Run Code Online (Sandbox Code Playgroud)

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


Sam*_* Lu 5

androidx.appcompat:appcompat:1.1.0漏洞还可以通过简单地调用解决getResources()Activity.applyOverrideConfiguration()

@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);
}
Run Code Online (Sandbox Code Playgroud)