无需获取所有视图及按钮ID实现Android应用语言切换的方案咨询
安卓无需逐个更新控件的全局语言切换解决方案
原方案失效原因
你直接修改Configuration的代码不会生效有两个核心问题:
- 你创建了携带新Locale的Context,但没有替换当前Activity正在使用的上下文,当前页面加载资源还是用的旧Locale的Context
- 没有触发Activity重新加载布局,系统不会自动刷新现有控件的文本内容,
updateConfiguration方法在安卓7.0以上已经被废弃,高版本系统不会响应这个修改。
完整实现步骤
安卓系统本身支持多语言资源匹配,只要你把对应语言的字符串放在对应资源目录下,只要全局修改了App的Locale配置,并且让Activity使用新Locale的Context重新加载布局,所有引用了@string资源的控件会自动加载对应语言的文本,完全不需要手动挨个赋值。
1. 封装Locale持久化和上下文替换工具类
首先创建LocaleHelper工具类,用于保存选中的语言、以及替换Activity的上下文:
import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import java.util.Locale; public class LocaleHelper { private static final String PREF_LANG = "selected_lang"; private static final String PREF_NAME = "lang_pref"; // 保存选中的语言到本地 public static void saveLocale(Context context, String langCode) { SharedPreferences sp = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); sp.edit().putString(PREF_LANG, langCode).apply(); } // 获取本地保存的语言,默认返回英文 public static String getSavedLocale(Context context) { SharedPreferences sp = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); return sp.getString(PREF_LANG, "en"); } // 替换上下文为指定语言的Context public static Context attachBaseContext(Context context) { String langCode = getSavedLocale(context); Locale locale = new Locale(langCode); Locale.setDefault(locale); Resources resources = context.getResources(); Configuration config = new Configuration(resources.getConfiguration()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { config.setLocale(locale); return context.createConfigurationContext(config); } else { config.locale = locale; resources.updateConfiguration(config, resources.getDisplayMetrics()); return context; } } }
2. 重写Activity的attachBaseContext方法
所有需要支持多语言的Activity都要重写这个方法,替换上下文:
@Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(LocaleHelper.attachBaseContext(newBase)); }
3. 选中语言后重启Activity即可自动刷新所有文本
不需要再逐个给控件赋值,只需要保存选中的语言后调用recreate()重启Activity,系统会自动加载对应语言的所有资源:
修改后的MainActivity完整代码:
import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 这里加载布局的时候会自动用当前Locale的资源,不需要手动赋值 setContentView(R.layout.activity_main); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.language); builder.setCancelable(false); builder.setItems(R.array.languages, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String[] languages_array = getResources().getStringArray(R.array.languages); String langCode = languages_array[which].equals("Chichewa") ? "ny" : "en"; // 保存选中的语言 LocaleHelper.saveLocale(MainActivity.this, langCode); // 重启Activity,自动加载新语言资源 recreate(); }}); AlertDialog alert = builder.create(); alert.show(); } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(LocaleHelper.attachBaseContext(newBase)); } }
注意事项
- 所有页面的文本必须引用
@string/xxx资源,不能在布局或者代码里硬编码写死文字 - 对应语言的字符串要放到对应资源目录下,比如齐切瓦语的字符串放到
res/values-ny/strings.xml,英文放到res/values-en/strings.xml - 如果需要全局所有页面都生效,可以在重启Activity的时候清空回退栈,重新打开首页,避免之前打开的页面还是旧语言
内容的提问来源于stack exchange,提问作者lewis machilika
相关产品推荐
相关产品推荐

