1. 程式人生 > >解決方案之Android 國際化資源完美相容6.0,7.0,8.0

解決方案之Android 國際化資源完美相容6.0,7.0,8.0

在Android世界中,一般App應用的語言是根據Android系統顯示的語言變化的,但是有時候有些應用需要單獨設定App的顯示語言。

Android 國際化實現

國際化一般最常用的是支援簡體中文和美式英文。
思路:

  1. 切換Project檢視
  2. 建立多個國家的資原始檔夾
  3. 呼叫語言切換工具類(獲取string.xml 通過Resource物件,然後更新)
  4. 在Application啟動的時候載入修改語言方法
  5. 建立一個Activity基類,方便隨時隨地重啟和替換掉所有介面的Context

1. 首先需要將專案切換到Project 檢視(必要)

在這裡插入圖片描述

2. 建立資原始檔夾(必要)

比如國際化需要支援簡體中文和美式英語,需要這三個string.xml

  • values 預設的字串資原始檔,必須有
  • values-zh-rCN 簡體中文字串資原始檔
  • values-en-rUS 美式英語字串資原始檔

在這裡插入圖片描述
格式規範: values-語言程式碼-r國家程式碼
例如:values-zh-rCN(中文)和values-en-rUS(英文)
這裡可以考慮使用一些輔助工具:

3. 中文和英文切換呼叫方法(必要)

MainActivity.java

  /**
     * App 語言切換成英文
     **/
    private void appLanguageSwitchToEnglish() {
        Locale locale=new Locale("en","US");
        //強制修改成英文
        LanguageUtil.changeAppLanguage(locale, true);
        //English 點選後按鈕文字修改為簡體中文
        loginPageSwitchLanguageButton.setText(getString(R.string.login_page_switch_language_Chinese_language));
        ToastTools.showLong(MyApplication.getContext(),"Current App Language Have Switch To English");
        //重啟App
        restartApplication();
    }
    /**
     * App語言切換成中文
     */
    private void appLanguageSwitchToChinese() {
        Locale chineseLocale=new Locale("zh","CN");
        //強制切換成中文簡體
        LanguageUtil.changeAppLanguage(chineseLocale, true);
        loginPageSwitchLanguageButton.setText(getString(R.string.login_page_switch_language_English_language));
        loginPageSwitchLanguageButton.invalidate();
        ToastTools.showLong(MyApplication.getContext(),"當前App語言已切換為簡體中文");
        //重啟應用
        restartApplication();
    }

4.語言切換工具類(必要)

LanguageUtil.java

public class LanguageUtil {

    public static Context appContext=MyApplication.getContext();

    /**
     * 更改應用語言
     * @param locale 語言地區
     * @param persistence 是否持久化
     */

    public static void changeAppLanguage(Locale locale, boolean persistence) {
        //獲取應用程式的所有資源物件
        Resources resources = MyApplication.getContext().getResources();
        //獲取螢幕引數
        DisplayMetrics metrics = resources.getDisplayMetrics();
        //獲取設定物件
        Configuration configuration = resources.getConfiguration();
        //如果API < 17
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.locale = locale;
            appContext= MyApplication.getContext();
        } else //如果 17 < = API < 25 Android 7.7.1
            if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N_MR1){
            configuration.setLocale(locale);
            appContext=MyApplication.getContext();
        }else{//API 25  Android 7.7.1
            configuration.setLocale(locale);
            configuration.setLocales(new LocaleList(locale));
            appContext=MyApplication.getContext().createConfigurationContext(configuration);
        }
        //更新配置資訊
        resources.updateConfiguration(configuration, metrics);
        //持久化
        if (persistence) {
            SharePreferencesTools.saveObjectToSharePreferences(MyApplication.getContext(), LanguageSwitchConstant.LANGUA_SWITCH_FILE_NAME, LanguageSwitchConstant.LANGUA_SWITCH_SELECTED_KEY,locale);
        }
    }

    /**
     * 獲取App當前語言
     * 如果存過資訊那麼以存的資訊為準否則取系統的配置資訊為準
     * @Return Locale
     * **/
    public static Locale getAppLocale() {
        //讀取本地配置檔案資訊
        Locale currentAppLocale=null;
        currentAppLocale=(Locale) SharePreferencesTools.readObjectFromSharePreferences(MyApplication.getContext(),LanguageSwitchConstant.LANGUA_SWITCH_FILE_NAME,LanguageSwitchConstant.LANGUA_SWITCH_SELECTED_KEY);
       if(currentAppLocale==null){
           currentAppLocale=getSystemLocale();
       }
        return currentAppLocale;
    }

    /******
     * 獲取當前系統語言
     */
    public static Locale getSystemLocale(){
        Locale currentSystemLocale;
        //API >= 24
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            currentSystemLocale = Resources.getSystem().getConfiguration().getLocales().get(0);
        } else {
            currentSystemLocale = Resources.getSystem().getConfiguration().locale;
        }
        return currentSystemLocale;
    }
}

5. MyApplication中呼叫(必要)

MyApplication.java

public class MyApplication extends Application {

    /***
     * 系統上下文
     */
    private static Context context;
    @Override
    public void onCreate() {
        super.onCreate();
        context=getApplicationContext();
        Locale currentAppLocale=LanguageUtil.getAppLocale();
        LanguageUtil.changeAppLanguage(currentAppLocale,false);
    }

    public static Context getContext(){
        return context;
    }
}

6. BaseActivity替換所有的Context

SmartBaseActivity.java

public class SmartBaseActivity extends AppCompatActivity{
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    /***
     * 重啟應用程式
     * */
    protected void restartApplication() {
        final Intent intent = MyApplication.getContext().getPackageManager().getLaunchIntentForPackage(getPackageName());
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
    }

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(LanguageUtil.appContext);
    }
}

7. SharePreferencesTools 儲存國際化狀態(必要)

SharePreferencesTools.java

public class SharePreferencesTools {

    /**
     * 方法描述: SharePreferences 儲存物件
     * 呼叫方法SharePreferencesSaveObject(Context context,String fileName,String key ,Object obj);
     * @param context  上下文物件
     * @param fileName SharePreference 檔名稱
     * @param key Key
     * @param obj 要儲存的物件
     * @return void
     * */
    /*******************SharePreferences 儲存物件 *****************************/
    public static void saveObjectToSharePreferences(Context context, String fileName, String key, Object obj){
        try {
            // 儲存物件
            SharedPreferences.Editor sharedata = context.getSharedPreferences(fileName,0).edit();
            //先將序列化結果寫到byte快取中,其實就分配一個記憶體空間
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            ObjectOutputStream os=new ObjectOutputStream(bos);
            //將物件序列化寫入byte快取
            os.writeObject(obj);
            //將序列化的資料轉為16進位制儲存
            String bytesToHexString = bytesToHexString(bos.toByteArray());
            //儲存該16進位制陣列
            sharedata.putString(key, bytesToHexString);
            sharedata.commit();
        } catch (IOException e) {
            e.printStackTrace();
            SmartLogUtils.debugInformation("儲存Obj失敗"+e.toString(),true);
        }
    }
    /**
     * desc:將陣列轉為16進位制
     * @param bArray
     * @return String
     */
    private static String bytesToHexString(byte[] bArray) {
        if(bArray == null){
            return null;
        }
        if(bArray.length == 0){
            return "";
        }
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }
    /*******************SharePreferences 儲存物件 *****************************/

    /**
     * 方法描述: 獲取SharePreferences儲存的Object物件
     * 呼叫方法     Object obj= readSharePreferencesObject(Context context,String fileName,String key );
     * @param context  上下文物件
     * @param filename 讀取檔名
     * @param key
     * @return 異常返回null,成功返回該物件
     */
    /*******************讀取 SharePreferences 儲存物件 *****************************/
    public static Object readObjectFromSharePreferences(Context context,String fileName,String key ){
        try {
            SharedPreferences sharedata = context.getSharedPreferences(fileName, 0);
            if (sharedata.contains(key)) {
                String string = sharedata.getString(key,"");
                if(TextUtils.isEmpty(string)){
                    return null;
                }else{
                    //將16進位制的資料轉為陣列,準備反序列化
                    byte[] stringToBytes = StringToBytes(string);
                    ByteArrayInputStream bis=new ByteArrayInputStream(stringToBytes);
                    ObjectInputStream is=new ObjectInputStream(bis);
                    //返回反序列化得到的物件
                    Object readObject = is.readObject();
                    return readObject;
                }
            }
        } catch (StreamCorruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //所有異常返回null
        return null;

    }
    /**
     * desc:將16進位制的資料轉為陣列
     * @param  data
     * @return
     */
    private static byte[] StringToBytes(String data){
        String hexString=data.toUpperCase().trim();
        if (hexString.length()%2!=0) {
            return null;
        }
        byte[] retData=new byte[hexString.length()/2];
        for(int i=0;i<hexString.length();i++)
        {
            int int_ch;  // 兩位16進位制數轉化後的10進位制數
            char hex_char1 = hexString.charAt(i); ////兩位16進位制數中的第一位(高位*16)
            int int_ch1;
            if(hex_char1 >= '0' && hex_char1 <='9')
                int_ch1 = (hex_char1-48)*16;   //// 0 的Ascll - 48
            else if(hex_char1 >= 'A' && hex_char1 <='F')
                int_ch1 = (hex_char1-55)*16; //// A 的Ascll - 65
            else
                return null;
            i++;
            char hex_char2 = hexString.charAt(i); ///兩位16進位制數中的第二位(低位)
            int int_ch2;
            if(hex_char2 >= '0' && hex_char2 <='9')
                int_ch2 = (hex_char2-48); //// 0 的Ascll - 48
            else if(hex_char2 >= 'A' && hex_char2 <='F')
                int_ch2 = hex_char2-55; //// A 的Ascll - 65
            else
                return null;
            int_ch = int_ch1+int_ch2;
            retData[i/2]=(byte) int_ch;//將轉化後的數放入Byte裡
        }
        return retData;
    }
    /*******************讀取 SharePreferences 儲存物件 *****************************/
}

8. 吐司工具類 (非必須)

/**
 * Toast 彈出資訊工具類,簡化程式碼編寫
 * @author fairy
 * */
public class SmartToastUtils{
    public static void showLong(String info) {
        Toast.makeText(MyApplication.getContext(),info, Toast.LENGTH_LONG).show();
    }
    public static void showShort(String info) {
        Toast.makeText(MyApplication.getContext(),info,Toast.LENGTH_SHORT).show();
    }
}

9. 日誌工具類(非必要)

public class SmartLogUtils {

    /***
     * 封裝日誌列印方法
     * @param  message 列印的訊息
     * @param  showMessage 是否顯示列印的訊息
     * **/
    public static void debugInformation(String message,Boolean showMessage){
        if(showMessage){
            int max_str_length = 2001 - DebugConstant.DEBUG_TAG.length();
            //大於4000時
            while (message.length() > max_str_length) {
                Log.e(DebugConstant.DEBUG_TAG, message.substring(0, max_str_length));
                message = message.substring(max_str_length);
            }
            //剩餘部分
            Log.e(DebugConstant.DEBUG_TAG,message);
        }
    }

    private final static String DEBUG_TAG="xingyun";
    /***
     * 封裝日誌列印方法
     * @param  message 列印的訊息
     * @param  showMessage 是否顯示列印的訊息
     * **/
    public static void showInfo(String message,Boolean showMessage){
        if(showMessage){
            int max_str_length = 2001 - DEBUG_TAG.length();
            //大於4000時
            while (message.length() > max_str_length) {
                Log.i(DEBUG_TAG, message.substring(0, max_str_length));
                message = message.substring(max_str_length);
            }
            //剩餘部分
            Log.i(DEBUG_TAG,message);
        }
    }

    /***
     * 封裝日誌列印方法
     * @param  message 列印的訊息
     * @param  showMessage 是否顯示列印的訊息
     * **/
    public static void showDebug(String message,Boolean showMessage){
        if(showMessage){
            int max_str_length = 2001 - DEBUG_TAG.length();
            //大於4000時
            while (message.length() > max_str_length) {
                Log.d(DEBUG_TAG, message.substring(0, max_str_length));
                message = message.substring(max_str_length);
            }
            //剩餘部分
            Log.d(DEBUG_TAG,message);
        }
    }

    public static void showError(String message,Boolean showMessage){
        if(showMessage){
            int max_str_length = 2001 - DEBUG_TAG.length();
            //大於4000時
            while (message.length() > max_str_length) {
                Log.e(DEBUG_TAG, message.substring(0, max_str_length));
                message = message.substring(max_str_length);
            }
            //剩餘部分
            Log.e(DEBUG_TAG,message);
        }
    }
}

本篇完~
如有疑問歡迎留言~