以前老是有開發者反饋我應用切換了語言,但是工具類獲取的 string
卻沒有發生改變。其實這個問題很簡單,你切換語言的 Context
只做用在了你的 Activity
上,並無對你的 Application
作一樣的操做,知道了這點,那麼解決問題就很簡單了,爲了省事,我給你們封裝了 LanguageUtils
,直接一行代碼即可完成多語言的切換,相似微信的語言切換分分鐘即可完成。java
Gradle:android
implementation 'com.blankj:utilcode:latest_version'
複製代碼
applySystemLanguage : 設置系統語言
applyLanguage : 設置語言
isAppliedLanguage : 是否設置了語言
getAppliedLanguage : 獲取設置的語言
getContextLanguage : 獲取上下文的語言
getAppContextLanguage : 獲取應用上下文的語言
getSystemLanguage : 獲取系統的語言
updateAppContextLanguage: 更新應用上下文語言
attachBaseContext : 若是設置語言無效則在 Activity#attachBaseContext 調用它
複製代碼
若是咱們的應用不設置 android:configChanges="locale|layoutDirection"
,那麼應用是跟隨系統語言設置的變化而變化的,好比你應用適配了英語(values-en-rUS
)和簡體中文(values-zh-rCN
),那麼你去設置裏切換成英語的話,返回到你應用中,你的 Activity
會從新建立一遍,把 Activity#Resource#Configuration#Locale
設置爲當前系統語言,這樣就達到了跟隨系統語言設置的變化而變化,但 Application
並無重啓,因此這就致使了一開說到的問題。git
要解決跟隨系統變化這一點的話,只須要在 Activity#onCreate
的生命週期中把 Application#Resource#Configuration#Locale
設置爲系統的 Locale
便可,那麼系統的 Locale
怎麼讀取呢,知道以前屏幕適配方案的人應該也能想到這一方式:Resources.getSystem().getConfiguration().locale
,這樣,咱們的 Application
便也切換成了系統語言,注意更新 Locale
須要兼容下高版本,調用具體代碼能夠參照以下:github
/** * Update the locale of applicationContext. * * @param destLocale The dest locale. * @param consumer The consumer. */
public static void updateAppContextLanguage(@NonNull Locale destLocale, @Nullable Utils.Consumer<Boolean> consumer) {
pollCheckAppContextLocal(destLocale, 0, consumer);
}
static void pollCheckAppContextLocal(final Locale destLocale, final int index, final Utils.Consumer<Boolean> consumer) {
Resources appResources = Utils.getApp().getResources();
Configuration appConfig = appResources.getConfiguration();
Locale appLocal = getLocal(appConfig);
setLocal(appConfig, destLocale);
// 因爲 updateConfigure 並不會立馬更新(本地測試小於 1ms 便會更新)config,因此須要後面的輪詢來監聽變化來作其餘處理(好比重啓應用)
Utils.getApp().getResources().updateConfiguration(appConfig, appResources.getDisplayMetrics());
if (consumer == null) return;
if (isSameLocale(appLocal, destLocale)) {
consumer.accept(true);
} else {
if (index < 20) {
UtilsBridge.runOnUiThreadDelayed(new Runnable() {
@Override
public void run() {
pollCheckAppContextLocal(destLocale, index + 1, consumer);
}
}, 16);
return;
}
Log.e("LanguageUtils", "appLocal didn't update.");
consumer.accept(false);
}
}
複製代碼
那麼若是是應用內切換語言呢?咱們能夠仿照系統切換語言的方式,重啓咱們的應用或者重啓全部的 Activity,在打開的 Activity#onCreate
中把 Activity
和 Application
的 Locale
都設置爲咱們設置的語言便可,固然,這份設置是須要保存下來的,根據你的需求來肯定是要保存在服務端仍是本地。相關代碼以下所示:微信
private static void applyLanguageReal(final Locale locale, final boolean isRelaunchApp) {
if (locale == null) {
// 後面的 true 使用的是 sp.commit,由於若是用 apply 的話,殺掉應用重啓會來不及保存
UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, VALUE_FOLLOW_SYSTEM, true);
} else {
UtilsBridge.getSpUtils4Utils().put(KEY_LOCALE, locale2String(locale), true);
}
Locale destLocal = locale == null ? getLocal(Resources.getSystem().getConfiguration()) : locale;
// 這個就是上面提到的函數
updateAppContextLanguage(destLocal, new Utils.Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (success) {
restart(isRelaunchApp);
} else {
// use relaunch app
UtilsBridge.relaunchApp();
}
}
});
}
private static void restart(final boolean isRelaunchApp) {
if (isRelaunchApp) {
UtilsBridge.relaunchApp();
} else {
for (Activity activity : UtilsBridge.getActivityList()) {
activity.recreate();
}
}
}
// 工具類調用此函數是在 ActivityLifecycleCallbacks#onActivityCreated 中
static void applyLanguage(final Activity activity) {
String spLocale = UtilsBridge.getSpUtils4Utils().getString(KEY_LOCALE);
if (TextUtils.isEmpty(spLocale)) {
return;
}
Locale destLocal;
if (VALUE_FOLLOW_SYSTEM.equals(spLocale)) {
destLocal = getLocal(Resources.getSystem().getConfiguration());
} else {
destLocal = string2Locale(spLocale);
}
if (destLocal == null) return;
updateConfiguration(activity, destLocal);
updateConfiguration(Utils.getApp(), destLocal);
}
private static void updateConfiguration(Context context, Locale destLocal) {
Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
setLocal(config, destLocal);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
複製代碼
基於以上分析:markdown
Application
的語言。LanguageUtils.applyLanguage(Locale.你要設置的語言[, false]); // 第二個參數可選擇性傳入,表明是否要重啓應用,false 的話是 recreate 全部 Activity,true 的話就是重啓應用
便可;LanguageUtils.applySystemLanguage([false]); // 參數和上面說的是否重啓應用同樣
便可。功能其實很簡單,但老是缺乏人能把它分析得透徹,從而作得很完美分享出來,但願我此次的分享能讓你看到這一點,從而提高你以後的技能。app
字節跳動大量招人中,歡迎向 blankj@qq.com 投遞您的簡歷。ide