Android N以编程方式更改语言

Kuv*_*uva 52 java android android-7.0-nougat

我发现非常奇怪的错误只能在Android N设备上重现.

在浏览我的应用程序时,有可能改变语言.这是改变它的代码.

 public void update(Locale locale) {

    Locale.setDefault(locale);

    Configuration configuration = res.getConfiguration();

    if (BuildUtils.isAtLeast24Api()) {
        LocaleList localeList = new LocaleList(locale);

        LocaleList.setDefault(localeList);
        configuration.setLocales(localeList);
        configuration.setLocale(locale);

    } else if (BuildUtils.isAtLeast17Api()){
        configuration.setLocale(locale);

    } else {
        configuration.locale = locale;
    }

    res.updateConfiguration(configuration, res.getDisplayMetrics());
}
Run Code Online (Sandbox Code Playgroud)

这段代码非常适合我的游览活动(通过recreate()调用),但在所有下一个活动中,所有String资源都是错误的.屏幕旋转修复它.我该怎么办这个问题?我应该以不同方式更改Android N的区域设置,还是只是系统错误?

PS这是我发现的.首次启动MainActivity(在我的巡演之后)Locale.getDefault()是正确的,但资源是错误的.但在其他活动中,它给了我错误的Locale和来自此语言环境的错误资源.旋转屏幕(或可能是其他一些配置更改)Locale.getDefault()是正确的.

Kuv*_*uva 98

好.最后我设法找到了解决方案.

首先,您应该知道在25 API Resources.updateConfiguration(...)中已弃用.所以你可以这样做:

1)您需要创建自己的ContextWrapper,它将覆盖baseContext中的所有配置参数.例如,这是我的ContextWrapper,可以正确地更改Locale.注意context.createConfigurationContext(configuration)方法.

public class ContextWrapper extends android.content.ContextWrapper {

    public ContextWrapper(Context base) {
        super(base);
    }

    public static ContextWrapper wrap(Context context, Locale newLocale) {
        Resources res = context.getResources();
        Configuration configuration = res.getConfiguration();

        if (BuildUtils.isAtLeast24Api()) {
            configuration.setLocale(newLocale);

            LocaleList localeList = new LocaleList(newLocale);
            LocaleList.setDefault(localeList);
            configuration.setLocales(localeList);

            context = context.createConfigurationContext(configuration);

        } else if (BuildUtils.isAtLeast17Api()) {
            configuration.setLocale(newLocale);
            context = context.createConfigurationContext(configuration);

        } else {
            configuration.locale = newLocale;
            res.updateConfiguration(configuration, res.getDisplayMetrics());
        }

        return new ContextWrapper(context);
    }
}
Run Code Online (Sandbox Code Playgroud)

2)以下是您应该在BaseActivity中执行的操作:

@Override
protected void attachBaseContext(Context newBase) {

    Locale newLocale;
    // .. create or get your new Locale object here.

    Context context = ContextWrapper.wrap(newBase, newLocale);
    super.attachBaseContext(context);
}
Run Code Online (Sandbox Code Playgroud)

注意:

如果要在某个位置更改应用程序中的区域设置,请记住重新创建活动.您可以使用此解决方案覆盖所需的任何配置.

  • 你在哪里从attacheBaseContext中获取持久化的语言环境对象? (4认同)
  • 在某些时候,我觉得最好抑制弃用。据我所知,使用已弃用的方法不会引起问题,而且这非常复杂。 (4认同)
  • 我第一次更改应用程序语言时一切都很好(EN - > ES),但是当我尝试更改语言(ES - > EN)时它不起作用.语言保持不变(ES).只有当我杀死应用程序并再次启动时,语言才是正确的(EN).知道为什么吗? (4认同)
  • 以我为例,它在Android N设备上引起了很多问题。对语言进行更改后,某些字符串资源可能是错误的(来自系统主语言环境)。我的LTR也有问题,因为我的应用程序支持阿拉伯语区域设置。 (3认同)
  • @AshishTiwari,目前,每次更改应用程序语言时,我都必须以编程方式重新启动应用程序:( (2认同)

thy*_*yzz 19

灵感来自各种代码(即:我们的Stackoverflow兄弟(喊出男孩们)),我制作了一个更简单的版本.所述ContextWrapper扩展是不需要的.

首先,假设您有2个语言的两个按钮,EN和KH.在onClick中为按钮保存语言代码SharedPreferences,然后调用activity recreate()方法.

例:

@Override
public void onClick(View v) {
    switch(v.getId()) {
        case R.id.btn_lang_en:
            //save "en" to SharedPref here
            break;
        case R.id.btn_lang_kh:
            //save "kh" to SharedPref here
            break;

        default:
        break;
    }
    getActivity().recreate();
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个静态方法ContextWrapper,可能在Utils类中返回(因为这就是我所做的,lul).

public static ContextWrapper changeLang(Context context, String lang_code){
    Locale sysLocale;

    Resources rs = context.getResources();
    Configuration config = rs.getConfiguration();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        sysLocale = config.getLocales().get(0);
    } else {
        sysLocale = config.locale;
    }
    if (!lang_code.equals("") && !sysLocale.getLanguage().equals(lang_code)) {
        Locale locale = new Locale(lang_code);
        Locale.setDefault(locale);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            config.setLocale(locale);
        } else {
            config.locale = locale;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            context = context.createConfigurationContext(config);
        } else {
            context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
        }
    }

    return new ContextWrapper(context);
}
Run Code Online (Sandbox Code Playgroud)

最后,从加载的语言代码SharedPreferences的所有活动'S attachBaseContext(Context newBase)方法.

@Override
protected void attachBaseContext(Context newBase) {
    String lang_code = "en"; //load it from SharedPref
    Context context = Utils.changeLang(newBase, lang_code);
    super.attachBaseContext(context);
}
Run Code Online (Sandbox Code Playgroud)

奖励:为了节省键盘上的手掌汗,我创建了一个LangSupportBaseActivity扩展Activity并使用最后一块代码的类.我还有其他所有活动LangSupportBaseActivity.

例:

public class LangSupportBaseActivity extends Activity{
    ...blab blab blab so on and so forth lines of neccessary code

    @Override
    protected void attachBaseContext(Context newBase) {
        String lang_code = "en"; //load it from SharedPref
        Context context = Utils.changeLang(newBase, lang_code);
        super.attachBaseContext(context);
    }
}

public class HomeActivity extends LangSupportBaseActivity{
    ...blab blab blab
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢你。我不得不绕过`if(!lang_code.equals(“”)&&!sysLocale.getLanguage()。equals(lang_code))`检查,因为在更改后(例如,用户在设置中),有时是`sysLocale.getLanguage ()`具有所需的语言值,但未明确设置语言环境,导致语言未更改。 (2认同)
  • '&&!sysLocale.getLanguage()。equals(lang_code)'if条件部分中的此条件应删除。因为这有时会带来错误的价值。 (2认同)

Ali*_*deh 15

自 Android 7.0+ 以来,我的应用程序的某些部分不再更改其语言。即使使用上面提出的新方法。应用程序和活动上下文的更新对我有帮助。这是 Activity 子类覆盖的 Kotlin 示例:

private fun setApplicationLanguage(newLanguage: String) {
    val activityRes = resources
    val activityConf = activityRes.configuration
    val newLocale = Locale(newLanguage)
    activityConf.setLocale(newLocale)
    activityRes.updateConfiguration(activityConf, activityRes.displayMetrics)

    val applicationRes = applicationContext.resources
    val applicationConf = applicationRes.configuration
    applicationConf.setLocale(newLocale)
    applicationRes.updateConfiguration(applicationConf,
            applicationRes.displayMetrics)
}

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(newBase)

    setApplicationLanguage("fa");
}
Run Code Online (Sandbox Code Playgroud)

注意:updateConfiguration 已被弃用,但无论如何,为每个活动创建配置上下文,保留一些字符串不变。