最近做了個小項目,領導要求添加可以切換中英文的功能,自己實現了這麼一個效果:
這裏說一下我的實現思路:
1.編寫不同語言環境的string.xml文件
2.編寫一個工具類修改程序的配置信息
3.銷燬重建activity使配置生效
4.重建activity後根據在主線程中存儲的語言標識修改按鈕圖標(右上角的按鈕)
1.編寫不同語言環境的string.xml文件
android studio生成不同語言環境的string.xml文件
參考:
Android studio 添加多語言支持
2.編寫一個工具類修改程序的配置信息
package com.phyplusinc.android.phymeshprovisioner.utils;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.Locale;
/**
* @Author: david.lvfujiang
* @Date: 2019/12/11
* @Describe:語言切換工具類
*/
public class LanguageUtil {
//弱引用持有Context
private static WeakReference<Context> weakReference;
public static String settingLanguage(Context context, ThreadLocal threadLocal) {
weakReference = new WeakReference<>(context);
//獲得res資源對象
Resources resources = weakReference.get().getResources();
//獲得設置對象
Configuration config = resources.getConfiguration();
//獲得屏幕參數:主要是分辨率,像素等。
DisplayMetrics dm = resources.getDisplayMetrics();
//使用ThreadLocal獲取主線程的數據
String language = (String) threadLocal.get();
if ("English".equals(language)) {
// 設置語言爲中文
config.locale = Locale.CHINESE;
threadLocal.set("Chinese");
Log.e("TAG", "Chinese");
} else {
//英語(美國)
config.locale = Locale.US;
threadLocal.set("English");
Log.e("TAG", "English");
}
//修改配置
resources.updateConfiguration(config, dm);
return language;
}
//獲取ThreadLocal對象
public static ThreadLocal getInstance() {
return Holder.threadLocal;
}
//在靜態內部類實現的單例模式
private static class Holder {
private static ThreadLocal threadLocal = new ThreadLocal<String>();
}
}
這個工具類主要的作用就是修改app的語言配置,這個過程需要
context
上下文,爲了防止內存泄漏我使用了弱引用持有context
。並且使用ThreadLocal
單例對象(靜態內部類實現單例模式)在主線程中存一個語言標識language
,ThreadLocal
的源碼與及應用場景可以參考我的這篇博客:android開發:ThreadLocal使用場景與源碼解析
然後在
activity
中需要切換語言時就調用工具類修改配置,然後銷燬重建activity配置纔會生效
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.img_language:
//修改配置
LanguageUtil.settingLanguage(MainActivity.this,LanguageUtil.getInstance());
//activity銷毀重建
MainActivity.this.recreate();
break;
default:
break;
}
activity銷毀重建會創建新的activity對象,系統會通過
onSaveInstanceState()
保存一些數據,activity重建時會回調onRestoreInstanceState()
方法。因此我重寫onRestoreInstanceState()
在其中獲取通過ThreadLocal
獲取主線程的語言標識來選擇切換不同的圖片。
@Override
public void onRestoreInstanceState(Bundle bundle){
super.onRestoreInstanceState(bundle);
Log.e("TAG","onRestoreInstanceState");
activityReset();
}
/**
* activity銷毀重建後會執行這個方法
*/
public void activityReset() {
//同一個對象在同一個線程中獲取的數據是一樣的,因爲每個線程都維護了一個ThreadLocalMap對象,key值是ThreadLocal
ThreadLocal<String> threadLocal = LanguageUtil.getInstance();
String language = threadLocal.get();
if ("English".equals(language)) {
imgLanguage.setImageResource(R.mipmap.chinese);
} else if ("Chinese".equals(language)) {
imgLanguage.setImageResource(R.mipmap.english);
}
}
這個例子功能其實很簡單,但是我考慮到的東西還挺多,單例模式、內存泄露、ThreadLocal等。因此在寫代碼的時候不要止單單實現功能而已,應該學會思考這樣寫有什麼問題嗎?有沒有更好的寫法?