Android N 以编程方式更改语言

新手上路,请多包涵

我发现了只在 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());
}

此代码在我的游览活动中效果很好(使用 recreate() 调用)但在接下来的所有活动中,所有字符串资源都是错误的。屏幕旋转修复它。我该怎么办这个问题?我应该以不同方式更改 Android N 的区域设置还是只是系统错误?

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

原文由 Kuva 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 489
2 个回答

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

首先,您应该知道在 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);
    }
}

  1. 以下是您应该在 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);
}

笔记:

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

原文由 Kuva 发布,翻译遵循 CC BY-SA 4.0 许可协议

受各种代码(即:我们的 Stackoverflow 团队(大声喊叫))的启发,我制作了一个更简单的版本。 ContextWrapper 扩展名是不必要的。

首先假设您有 2 个按钮用于 2 种语言,EN 和 KH。在按钮的 onClick 中,将语言代码保存到 SharedPreferences ,然后调用活动 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();
}

然后创建一个返回 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);
}

最后,在 所有活动的 attachBaseContext(Context newBase) 方法中从 SharedPreferences 加载语言代码。

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

奖励:为了节省键盘上的手掌汗水,我创建了一个 LangSupportBaseActivity 扩展了 Activity 代码。我还有所有其他活动 extends 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
}

原文由 thyzz 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题