安卓 N 以编程方式更改语言

2022-08-31 14:53:44

我发现了非常奇怪的错误,仅在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());
}

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

附言:这是我的发现。在MainActivity的第一次开始(在我的旅行之后)是正确的,但资源是错误的。但在其他活动中,它为我提供了错误的 Locale 和来自此区域设置的错误资源。旋转屏幕(或者可能是其他一些配置更改)是正确的。Locale.getDefault()Locale.getDefault()


答案 1

还行。最后,我设法找到了解决方案。

首先,您应该知道,在25中,API已被弃用。因此,您可以执行如下操作:Resources.updateConfiguration(...)

1)你需要创建自己的 ContextWrapper,它将覆盖 baseContext 中的所有配置参数。例如,这是我的上下文包装器,它正确地改变了区域设置。注意方法。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);
    }
}

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);
}

注意:

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


答案 2

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

首先,假设您有 2 个按钮,用于 2 种语言,EN 和 KH。在 onClick 中,按钮将语言代码保存到 中,然后调用 activity 方法。SharedPreferencesrecreate()

例:

@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();
}

然后创建一个返回的静态方法,也许在Utils类中(coz这就是我所做的,lul)。ContextWrapper

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);
}

最后,从 ALL ACTIVITY 的方法中加载语言代码。SharedPreferencesattachBaseContext(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);
}

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

例:

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
}

推荐