天天看點

隻需一行代碼完成多語言切換

隻需一行代碼完成多語言切換

背景

之前總是有開發者回報我應用切換了語言,可是工具類擷取的

string

卻沒有發生改變。其實這個問題很簡單,你切換語言的

Context

隻作用在了你的

Activity

上,并沒有對你的

Application

做同樣的操作,知道了這點,那麼解決問題就很簡單了,為了省事,我給大家封裝了

LanguageUtils

,直接一行代碼便可完成多語言的切換,類似微信的語言切換分分鐘便可完成。

使用

Gradle:

implementation 'com.blankj:utilcode:latest_version'
           

APIs

語言相關 

applySystemLanguage: 應用系統語言
applyLanguage      : 應用語言
           

原理

如果我們的應用不設定

android:configChanges="locale|layoutDirection"

,那麼應用是跟随系統語言設定的變化而變化的,比如你應用适配了英語(

values-en-rUS

)和簡體中文(

values-zh-rCN

),那麼你去設定裡切換成英語的話,傳回到你應用中,你的

Activity

會重新建立一遍,把

Activity#Resource#Configuration#Locale

設定為目前系統語言,這樣就達到了跟随系統語言設定的變化而變化,但

Application

并沒有重新開機,是以這就導緻了一開說到的問題。

要解決跟随系統變化這一點的話,隻需要在

Activity#onCreate

的生命周期中把

Application#Resource#Configuration#Locale

設定為系統的

Locale

即可,那麼系統的

Locale

怎麼讀取呢,知道之前螢幕适配方案的人應該也能想到這一方式:

Resources.getSystem().getConfiguration().locale

,這樣,我們的

Application

便也切換成了系統語言,注意更新

Locale

需要相容下高版本,調用具體代碼可以參照如下:

private static void updateLanguage(Context context, Locale locale) {
    Resources resources = context.getResources();
    Configuration config = resources.getConfiguration();
    Locale contextLocale = config.locale;
    if (equals(contextLocale.getLanguage(), locale.getLanguage())
            && equals(contextLocale.getCountry(), locale.getCountry())) {
        return;
    }
    DisplayMetrics dm = resources.getDisplayMetrics();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        config.setLocale(locale);
        context.createConfigurationContext(config);
    } else {
        config.locale = locale;
    }
    resources.updateConfiguration(config, dm);
}
           

那麼如果是應用内切換語言呢?我們可以仿照系統切換語言的方式,把我們自己所有的

Activity

全關掉,然後啟動首頁的

Activity

即可,在打開的

Activity#onCreate

中把

Activity

Application

Locale

都設定為我們設定的語言即可,當然,這份設定是需要儲存下來的,根據你的需求來确定是要儲存在服務端還是本地。那麼怎麼關閉所有的

Activity

呢?我們可以通過增加

Intent

的 flag 為

Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK

即可,相關代碼如下所示:

private static void applyLanguage(@NonNull final Locale locale,
                                  final String activityClassName,
                                  final boolean isFollowSystem) {
    if (isFollowSystem) {// 如果是跟随系統,那麼 sp 就什麼都不存
        SPUtils.getInstance().put(KEY_LOCALE, "");
    } else {// 否則把設定的語言儲存下來,在 onCreate 中應用該語言
        String localLanguage = locale.getLanguage();
        String localCountry = locale.getCountry();
        SPUtils.getInstance().put(KEY_LOCALE, localLanguage + "$" + localCountry);
    }
    updateLanguage(Utils.getApp(), locale);// 更新 Application 的語言
    Intent intent = new Intent();
    String realActivityClassName// 如果傳入的 activityClassName 為空,那麼啟動 launcher Activity。
            = TextUtils.isEmpty(activityClassName) ? getLauncherActivity() : activityClassName;
    intent.setComponent(new ComponentName(Utils.getApp(), realActivityClassName));
    intent.addFlags(
            Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK
    );
    Utils.getApp().startActivity(intent);// 關閉其他 Activity 并啟動 realActivityClassName 的 Activity
}

// 工具類調用此函數是在 ActivityLifecycleCallbacks#onActivityCreated 中
static void applyLanguage(@NonNull final Activity activity) {
    final String spLocale = SPUtils.getInstance().getString(KEY_LOCALE);// 擷取儲存的語言
    if (TextUtils.isEmpty(spLocale)) {// 為空說明是跟随系統走,那麼更新系統語言即可
        Locale sysLocale = Resources.getSystem().getConfiguration().locale;
        updateLanguage(Utils.getApp(), sysLocale);
        updateLanguage(activity, sysLocale);
        return;
    }
    // 讀取 sp 儲存下來的語言并應用該語言
    String[] language_country = spLocale.split("\\$");
    if (language_country.length != 2) {
        Log.e("LanguageUtils", "The string of " + spLocale + " is not in the correct format.");
        return;
    }
    Locale settingLocale = new Locale(language_country[0], language_country[1]);
    updateLanguage(Utils.getApp(), settingLocale);
    updateLanguage(activity, settingLocale);
}
           

基于以上分析:

  • 如果應用是跟随系統設定語言來切換的話,那麼直接依賴我的工具類即可,它會自動幫你更新

    Application

    的語言。
  • 如果需要應用内切換語言的話,隻需在你切換語言的地方調用

    LanguageUtils.applyLanguage(Locale.你要設定的語言, "com.blankj.launcher.pkg.MainActivity")

    即可;
  • 如果需要應用内切換語言變為跟随系統設定語言,那麼調用

    LanguageUtils.applySystemLanguage("");

    即可。

結語

功能其實很簡單,但總是缺少人能把它分析得透徹,進而做得很完美分享出來,希望我這次的分享能讓你看到這一點,進而提升你之後的技能。

最後

如果你看到了這裡,覺得文章寫得不錯就給個贊呗!歡迎大家評論讨論!如果你覺得那裡值得改進的,請給我留言。一定會認真查詢,修正不足,定期免費分享技術幹貨。謝謝!

隻需一行代碼完成多語言切換

繼續閱讀