Android多語言那點事(支持8.0+)

起因

我們在開發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);
   }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章