Android多语言那点事(支持8.0+)

作者: af83084249b7 | 来源:发表于2018-06-01 19:59 被阅读293次

    起因

    我们在开发app可能会拓展国外市场,那么对包含英语在内的其它语言支持就很有必要了。

    效果

    multilanguage.gif

    思路

    一:添加相关资源文件,并引用。
    二:设置configuration,configuration里面指定语言类型。
    三:在需要时候更换configuration即可。

    实现

    在res的values文件夹下新建相关语言类型的资源文件

    右键新建资源文件,选择Locale,点击 >> 按钮


    a.png

    选择Language,以及地区(any region)即可


    b.png

    最后 文件名字和其他语言文件名字一样,strings即可。

    在MyApplication里面的onCreate和onConfigurationChanged方法里面添加语言相关处理(onConfigurationChanged是为了处理横竖屏切换问题),给应用上下文对象添加configuration,configuration里面指定了当前语言。

    public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        languageWork();
    }
    
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        languageWork();
    }
    
    private void languageWork() {
        //自己写的工具包(如下)
        Locale locale = LanguageUtil.getLocale(this);
        LanguageUtil.updateLocale(this, locale);
    }
    }
    

    LanguageUtil如下(没整理过的小伙伴直接用即可),为了保证语言从A切换到B,在之后启动应用依旧使用B语言,我们需要将B语言存入本地。下次启动应用,设置即可。

    public class LanguageUtil {
    /**
     * 中文
     */
    public static final Locale LOCALE_CHINESE = Locale.CHINESE;
    /**
     * 英文
     */
    public static final Locale LOCALE_ENGLISH = Locale.ENGLISH;
    /**
     * 俄文
     */
    public static final Locale LOCALE_RUSSIAN = new Locale("ru");
    
    private static final String LOCALE_SP = "LOCALE_SP";
    private static final String LOCALE_SP_KEY = "LOCALE_SP_KEY";
    
    
    
    
    public static Locale getLocale(Context context) {
        SharedPreferences spLocale = context.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE);
        String localeJson = spLocale.getString(LOCALE_SP_KEY, "");
        Gson gson = new Gson();
        return gson.fromJson(localeJson, Locale.class);
    }
    
    
    private static void setLocale(Context pContext, Locale pUserLocale) {
        SharedPreferences spLocal = pContext.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE);
        SharedPreferences.Editor edit = spLocal.edit();
        String json = new Gson().toJson(pUserLocale);
        edit.putString(LOCALE_SP_KEY, json);
        edit.apply();
    }
    
    
    public static boolean updateLocale(Context context, Locale locale) {
        if (needUpdateLocale(context, locale)) {
            Configuration configuration = context.getResources().getConfiguration();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                configuration.setLocale(locale);
            } else {
                configuration.locale = locale;
            }
            DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
            context.getResources().updateConfiguration(configuration, displayMetrics);
            setLocale(context, locale);
            return true;
        }
        return false;
    }
    
    public static boolean needUpdateLocale(Context pContext, Locale newUserLocale) {
        return newUserLocale != null && !getCurrentLocale(pContext).equals(newUserLocale);
    }
    public static Locale getCurrentLocale(Context context) {
        Locale locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0有多语言设置获取顶部的语言
            locale = context.getResources().getConfiguration().getLocales().get(0);
        } else {
            locale = context.getResources().getConfiguration().locale;
        }
        return locale;
    }
    }
    

    进行切换,主要触发动作是activity的recreate()(切换使用新的configuration)。所有的activity在activityManager里面进行管理。只需将其他(除了当前语言选择activity)的所有activity进行recreate(),即可。languageUtil同时进行了是否需要切换语言的判定。如果当前语言和要选择的一致,则无需再做处理)

     public void onClick(View view) {
        boolean need = false;
        switch (view.getId()) {
            case R.id.chinese:
                need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_CHINESE);
                if (need) {
                    //自己写的常用activity管理工具
                    ActivityManager.getInstance().recreateAllOtherActivity(this);
                    Toast.makeText(this, "change to chinese", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.english:
                need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_ENGLISH);
                if (need) {
                    ActivityManager.getInstance().recreateAllOtherActivity(this);
                    Toast.makeText(this, "change to english", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.russian:
                need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_RUSSIAN);
                if (need) {
                    ActivityManager.getInstance().recreateAllOtherActivity(this);
                    Toast.makeText(this, "change to russian", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
    

    ActivityManager如下

     public class ActivityManager {
    private static final Stack<Activity> sActivityStack = new Stack<>();
    private static ActivityManager sActivityManager;
    
    private ActivityManager() {
    }
    
    public Stack<Activity> getActivityStack() {
        return sActivityStack;
    }
    
    /**
     * 单一实例
     */
    public static ActivityManager getInstance() {
        if (sActivityManager == null) {
            synchronized (ActivityManager.class) {
                sActivityManager = new ActivityManager();
            }
        }
        return sActivityManager;
    }
    
    /**
     * 添加Activity到堆栈
     */
    public void addActivity(Activity activity) {
        sActivityStack.add(activity);
    }
    
    /**
     * 删除堆栈中的Activity
     */
    public void removeActivity(Activity activity) {
        if (sActivityStack.isEmpty()) {
            return;
        }
        sActivityStack.remove(activity);
    }
    
    /**
     * 获取当前Activity(堆栈中最后一个压入的)
     */
    public Activity currentActivity() {
    
        Activity activity = sActivityStack.lastElement();
        return activity;
    }
    
    /**
     * 结束当前Activity(堆栈中最后一个压入的)
     */
    public void finishActivity() {
        Activity activity = sActivityStack.lastElement();
        finishActivity(activity);
    }
    
    /**
     * 结束指定的Activity
     */
    public void finishActivity(Activity activity) {
        if (activity != null) {
            sActivityStack.remove(activity);
            activity.finish();
        }
    }
    
    /**
     * 结束指定类名的Activity
     */
    public void finishActivity(Class<?> cls) {
        for (Activity activity : sActivityStack) {
            if (activity.getClass().equals(cls)) {
                finishActivity(activity);
                return;
            }
        }
    
    }
    
    //获取指定类名的Activity
    public Activity getActivity(Class<?> cls) {
        for (Activity activity : sActivityStack) {
            if (activity.getClass().equals(cls)) {
                return activity;
            }
        }
        return null;
    }
    
    /**
     * 结束所有Activity
     */
    public void finishAllActivity() {
        for (int i = 0, size = sActivityStack.size(); i < size; i++) {
            if (null != sActivityStack.get(i)) {
                sActivityStack.get(i).finish();
            }
        }
        sActivityStack.clear();
    }
    
    public void finishAllOtherActivity(Activity activity) {
        for (int i = 0, size = sActivityStack.size(); i < size; i++) {
            if (null != sActivityStack.get(i) && sActivityStack.get(i) != activity) {
                sActivityStack.get(i).finish();
            }
        }
        sActivityStack.clear();
    }
    
    public void recreateAllOtherActivity(Activity activity) {
        for (int i = 0, size = sActivityStack.size(); i < size; i++) {
            if (null != sActivityStack.get(i) && sActivityStack.get(i) != activity) {
                sActivityStack.get(i).recreate();
            }
        }
    }
    
    /**
     * 退出应用程序
     */
    public void AppExit() {
        try {
            finishAllActivity();
            System.exit(0);
        } catch (Exception e) {
        }
        }
       }
    

    将app的所有acitivity进行添加和移除,可以在BaseActivity里面进行。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityManager.getInstance().addActivity(this);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityManager.getInstance().removeActivity(this);
    }
    

    以上步骤,我们的语言切换算是完成了。但是,在API 26+以上版本,我们需要额外添加如下代码做兼容,没啥说的,SDK变动而已,跟着SDK走咯~(在activity或者BaseActivity添加)

     @Override
    protected void attachBaseContext(Context newBase) {
        Context context = languageWork(newBase);
        super.attachBaseContext(context);
    
     }
    
    private Context languageWork(Context context) {
        // 8.0及以上使用createConfigurationContext设置configuration
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return updateResources(context);
        } else {
            return context;
        }
       }
    
    @RequiresApi(api = Build.VERSION_CODES.O)
    private Context updateResources(Context context) {
        Resources resources = context.getResources();
        Locale locale = LanguageUtil.getLocale(context);
        if (locale==null) {
            return context;
        }
        Configuration configuration = resources.getConfiguration();
        configuration.setLocale(locale);
        configuration.setLocales(new LocaleList(locale));
        return context.createConfigurationContext(configuration);
       }
    

    完工~

    地址:https://github.com/HoldMyOwn/MultiLanguage

    相关文章

      网友评论

      本文标题:Android多语言那点事(支持8.0+)

      本文链接:https://www.haomeiwen.com/subject/nnuksftx.html