代码之家  ›  专栏  ›  技术社区  ›  Shahzeb Khan

Android在第二次更改区域设置后从默认字符串文件(strings.xml)加载值

  •  1
  • Shahzeb Khan  · 技术社区  · 7 年前

    我正在开发一个Android应用程序,我只需一个按钮就可以在主屏幕上更改区域设置(英语到阿拉伯语)。它在主屏幕上运行良好,但当我多次更改语言时,问题就出现了。 按照以下步骤重新生成:

    • 在主(登录)屏幕上,当前语言是 English 我把它改成 Arabic . (工程精细)
    • 转到“注册”或“忘记密码”页,此时语言已更改。( 阿拉伯语的 )
    • 返回主屏幕并将区域设置更改回 英语 阿拉伯语的 . (在登录屏幕上工作)
    • 转到注册页,现在方向已更改,但字符串已从阿拉伯语加载。(当前语言为 英语 )

    这是我更改区域设置的代码。

    import android.app.Activity;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.res.Configuration;
    import android.preference.PreferenceManager;
    import android.support.v4.text.TextUtilsCompat;
    import android.support.v4.view.ViewCompat;
    import android.view.View;
    
    import java.util.Locale;
    
    public class LocaleSettings {
    
    public static final String LANGUAGE_ENGLISH = "en";
    public static final String LANGUAGE_ARABIC = "ar";
    public static final String CURRENT_LANGUAGE = "currentLanguage";
    
    /**
     * Loads the current language of application
     *
     * @param context current context, pass "this" for current view context
     */
    public static void loadLocal(Context context) {
        setLocal(context, PreferenceManager.getDefaultSharedPreferences(context).getString(CURRENT_LANGUAGE, ""));
    }
    
    /**
     * This fucntion sets the application language
     *
     * @param context - current context. pass "this" for current view context
     * @param lang    Language String, i.e. "en" or "ar"
     */
    public static void setLocal(Context context, String lang) {
        Locale locale = new Locale(lang);
        Locale.setDefault(locale);
        Configuration config = new Configuration();
        config.setLocale(locale);
        context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
    
        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = pref.edit();
        editor.putString(CURRENT_LANGUAGE, lang);
        editor.apply();
        editor.commit();
    }
    
    /**
     * Use to change application language using current context
     *
     * @param context pass "this" for current view context
     */
    public static void switchLanguage(Context context) {
        if (getCurrentLanguage(context).equals(LANGUAGE_ENGLISH))
            setLocal(context, LANGUAGE_ARABIC);
        else
            setLocal(context, LANGUAGE_ENGLISH);
    }
    
    /**
     * Get application current active language
     *
     * @param context pass "this" for current view context
     * @return String - language string i.e. en or ar
     */
    public static String getCurrentLanguage(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getString(CURRENT_LANGUAGE, "");
    }
    
    public static boolean isRTL(String locale) {
        return TextUtilsCompat.getLayoutDirectionFromLocale(new Locale(locale)) == ViewCompat.LAYOUT_DIRECTION_RTL ? true : false;
    }
    
    public static void enforceDirectionIfRTL(Context context){
        if(isRTL(getCurrentLanguage(context))){
            ((Activity) context).getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
        }
    
    }
    

    }

    这是登录活动的代码

    public class LoginActivity extends AppCompatActivity {
    
        private Button loginButton = null;
        private EditText account_no = null;
        private EditText password = null;
        final UserApi userApi = JoezdanServiceGenerator.createService(UserApi.class);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            LocaleSettings.loadLocal(this);
            setContentView(R.layout.activity_login);
    
            configureLanaguageButton();
    
        }
    
        private void configureLanaguageButton() {
    
            final ImageButton selectLocale = (ImageButton) findViewById(R.id.btnSelectLanguage);
            selectLocale.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    LocaleSettings.switchLanguage(LoginActivity.this);
                    recreate();
                }
            });
    
        }
    
    ... eliminating irrelevant code
    }
    

    这是我的第一个Android应用程序,如果有错误请原谅我。事先谢谢。

    2 回复  |  直到 7 年前
        1
  •  0
  •   Hossam Hassan    7 年前

    首先,您需要确保在用户更改本地之后,关闭所有活动并重新启动应用程序,如下所示

    Intent intent = new Intent(AcSettingsView.this, MainActivityView.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    finishAffinity();
    

    另一件要注意的事情是确保每次应用程序启动时都设置本地人。 像这样出现在你的第一个屏幕上

    helper = new PreferenceHelper(this);
            String lang = helper.getData(Constants.LANGUAGE_CODE);
                if (eng) {
                    Utility.setLocale(getBaseContext(), Constants.ENGLISH_CODE);
                } else {
                    Utility.setLocale(getBaseContext(), Constants.ARABIC_CODE);
                }
    
        2
  •  1
  •   nhp    7 年前

    从Android文档:

    默认情况下,Android使用设备的区域设置来选择适当的语言相关资源。大多数时候这种行为足以 常见的 应用。

    在内部更改语言是一个例外。

    首先,请阅读 this documentation 承认设计的缺陷。

    总而言之,我想提两件事:

    1. updateConfiguration 已弃用,因此我们需要另一个版本来支持向后兼容。
    2. 我们需要超越 attachBaseContext 以反映变化的每一项活动。

    实现方法如下:

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);
    
        return context.createConfigurationContext(configuration);
    }
    
    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Resources resources = context.getResources();
    
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        configuration.setLayoutDirection(locale);
    
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
        return context;
    }
    

    为了支持向后兼容,请在更改语言之前检查版本:

    public static Context setLocale(Context context, String language) {
        // You can save SharedPreference here
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }
    
        return updateResourcesLegacy(context, language);
    }
    

    在你 LoginActivity ,更改区域设置后,不必重新创建活动,您可以获取资源,然后更改 TextView 手动。

    Context context = LocaleUtils.setLocale(this, lang);
    Resources resources = context.getResources();
    yourFirstTextView.setText(resources.getString(R.string.your_first_text_res)
    // ... yourSecondTextView....
    

    在每个活动中,要反映更改,请添加此函数:

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(LocaleUtils.onAttach(newBase));
    }
    

    顺便说一句,有个bug,您不能更改的标题语言 Toolbar . 在你 onCreate() ,手动调用此函数, setTitle("your Title")

    我知道这些问题很难看,解决方法也有点老套。但让我们试试看。如果这对你有帮助,请告诉我。:)

    完整的源代码可以在这里找到: https://github.com/gunhansancar/ChangeLanguageExample/blob/master/app/src/main/java/com/gunhansancar/changelanguageexample/helper/LocaleHelper.java

    关于greate文章: https://gunhansancar.com/change-language-programmatically-in-android/

    推荐文章