解決方案之Android 國際化資源完美相容6.0,7.0,8.0
阿新 • • 發佈:2018-12-15
在Android世界中,一般App應用的語言是根據Android系統顯示的語言變化的,但是有時候有些應用需要單獨設定App的顯示語言。
Android 國際化實現
國際化一般最常用的是支援簡體中文和美式英文。
思路:
- 切換Project檢視
- 建立多個國家的資原始檔夾
- 呼叫語言切換工具類(獲取string.xml 通過Resource物件,然後更新)
- 在Application啟動的時候載入修改語言方法
- 建立一個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);
}
}
}
本篇完~
如有疑問歡迎留言~