热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android多语言适配的示例代码(兼容7.0+)

一、前言 1、安卓系统本身对多语言适配就提供了一套框架和API。我们就直接用就可以了。 2、更换语言必须recreate Activit

一、前言

1、安卓系统本身对多语言适配就提供了一套框架和API。我们就直接用就可以了。

2、更换语言必须recreate Activity。目前,没见过可以不重建的方法。常用App,也都是重建的,可以看的到。

3、兼容性问题。现在越来越多设备都是安卓7.0+新手机的安卓版本会更高(安卓8.0+),所以适配是必要的。

4、目前,网上大部分相关文章都是不兼容7.0+的,具体做法一搜一大把。

二、具体做法

1、多语言文件

文件夹命名参考下面博客(网上有很多):

多国语言value文件夹命名

value默认放英文的资源文件,简体中文文件夹命名为values-zh-rCN,不需要翻译的设置translatable如下:

代码如下:

You App English Name

2、多语言工具类

public class LanguageUtils {
 public static final String CHINESE_SIMPLE = "zh_CN";
 public static final String ENGLISH = "en";
 public static final String AUTO = "auto";
 private static final String TAG = "LanguageUtils";
 //public static final String[] LOCALES = Utils.getContext().getResources().getStringArray(R.array.locales);

 private LanguageUtils() {
  throw new UnsupportedOperationException("u can't instantiate me...");
 }

 public static void setSystemDefaultLocale(Locale locale) {

 }

 public static boolean isSetValue(Context context) {
  Locale currentLocale = context.getResources().getConfiguration().locale;
  return currentLocale.equals(getSetLocale());
 }

 private static Locale getSetLocale() {
  String locale = SPUtils.getInstance(BaseConstants.SP.NAME_APP_SETTINGS).getString(BaseConstants.SP.KEY_LANGUAGE, LanguageUtils.AUTO);
  if (locale.equals(LanguageUtils.AUTO)) {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    return Resources.getSystem().getConfiguration().getLocales().get(0);//解决了获取系统默认错误的问题
   } else {
    return Locale.getDefault();
   }
  }
  String[] array = locale.split("_");
  String language = array[0];
  if (array.length > 1) {
   String country = array[1];
   return new Locale(language, country);
  }
  return new Locale(language);
 }

 public static int getSetIndex() {
  String languageSet = SPUtils.getInstance(BaseConstants.SP.NAME_APP_SETTINGS).getString(BaseConstants.SP.KEY_LANGUAGE, LanguageUtils.AUTO);
  int localeIndex = 0;
  switch (languageSet) {
   case LanguageUtils.AUTO:
    localeIndex = 0;
    break;
   case LanguageUtils.CHINESE_SIMPLE:
    localeIndex = 1;
    break;
   case LanguageUtils.ENGLISH:
    localeIndex = 2;
    break;
  }
  return localeIndex;
 }

 public static Context wrapContext(Context context) {
  Resources resources = context.getResources();
  Locale locale = LanguageUtils.getSetLocale();

  Configuration cOnfiguration= resources.getConfiguration();
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
   configuration.setLocale(locale);
   LocaleList localeList = new LocaleList(locale);
   LocaleList.setDefault(localeList);
   configuration.setLocales(localeList);
  } else {
   configuration.setLocale(locale);
  }
  return context.createConfigurationContext(configuration);
 }

 public static void applyChange(Context context) {
  Resources res = context.getResources();
  DisplayMetrics dm = res.getDisplayMetrics();
  Configuration cOnf= res.getConfiguration();

  Locale locale = getSetLocale();
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
   conf.setLocale(locale);
   LocaleList localeList = new LocaleList(locale);
   LocaleList.setDefault(localeList);
   conf.setLocales(localeList);
  } else {
   conf.setLocale(locale);
  }
  res.updateConfiguration(conf, dm);
 }
}

3、代码分析&兼容7.0+

3.1、如何获取系统的语言设置,也就是7.0+你选择auto,可以正确切换。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    return Resources.getSystem().getConfiguration().getLocales().get(0);//解决了获取系统默认错误的问题
   } else {
    return Locale.getDefault();
   }

看到这篇文章的你,可能已经看过网上很多其他相关的文章,应该知道,7.0+系统有个很奇怪的地方:

如果你在app内切换了语言(比如说是英文),且该语言和系统的设置(比如说是中文)不同,那么你再次切换语言并选择auto时,通过Locale.getDefault()获取会错误,或者你通过LocaleList.get(0)也是错误的,你之前选择的语言(英文)排序被提前了。有些文章的解决方案是在app打开时持久化系统设置,这样你切换app的语言就不会影响你获取系统的设置,但这样没必要,太麻烦(应该是不知道上面的方法)。

7.0+的系统设置也看的出差别,以前,设置系统语言直接选择就可以了,现在你要先添加,然后再排序,排在第一个的才是系统显示的语言!

3.2、写个BaseActivity作为所有Activity父类

新建一个BaseActivity用于继承,重写:

@Override
 protected void attachBaseContext(Context newBase) {
  super.attachBaseContext(LanguageUtils.wrapContext(newBase));
 }

然后在切换语言后,你要recreate Activity。这个在哪调用就看具体需求了。你可以像微信那样,清空栈,然后直接重启到主界面,也可以在设置界面recreate,但栈内其他Activity,也要想办法通知recreate。

3.3、屏蔽系统设置改变

如果app的语言选项不是auto,那么系统语言设置修改时,app就不应该跟着系统变,而是按照自己设置的语言显示。写一个类继承于Application(注意要在manifest配置哦,不然无效的)

public class MyApp extends Application {
 private Configuration deltaConfig;

@Override
 public void onConfigurationChanged(Configuration newConfig) {
  LogUtils.d(TAG, "调用了onConfigurationChanged");
  int diff = newConfig.diff(deltaConfig);
  String languageSet = SPUtils.getInstance(AppConstants.SP.NAME_APP_SETTINGS).getString(AppConstants.SP.KEY_LANGUAGE, LanguageUtils.AUTO);
  if (languageSet.equals(LanguageUtils.AUTO)) {//看app语言设置是不是auto,是的话不管,直接super
   super.onConfigurationChanged(newConfig);
   deltaCOnfig= newConfig;
  } else if (diff != ActivityInfo.CONFIG_LOCALE) {//这个Configuration更改是不是语言,不是的话,也不管
   super.onConfigurationChanged(newConfig);
   deltaCOnfig= newConfig;
  }
   //这里使系统设置语言无效
   //相当于省略了
   //else{
   // return;
   //}
 }

 @Override
 public void onCreate() {
  super.onCreate();
  //app打开时记录系统设置
  deltaCOnfig= getApplicationContext().getResources().getConfiguration();
  LanguageUtils.applyChange(getApplicationContext());
  }
 }
}

3.4、其他问题

Application的Context也要更新

LanguageUtils.applyChange(context);
LanguageUtils.applyChange(context.getApplicationContext());

但即使这样,还是有点问题,主要在于:

如果Activity的Title你是在manifest中定义的,如下label:

那么,即使你更新了ApplicationContext,有些Activity也有可能不生效,而且每次都还不一样,这个没法复现(很迷)。不知道是不是系统bug(测试系统是一加3 氢OS 8.0),或者是有其他更好的写法?

针对这个问题,只要在activity oncreate() 里setTitle()就好了。这样是不会有什么问题的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文详细介绍了如何在Python3环境中配置Appium1.4.6,并指导如何连接模拟器进行自动化测试。通过本文,您将了解从环境搭建到模拟器连接的完整流程。 ... [详细]
  • 本文介绍了如何利用Java中的URLConnection类来实现基本的网络爬虫功能,包括向目标网站发送请求、接收HTML响应、解析HTML以提取所需信息,并处理可能存在的递归爬取需求。 ... [详细]
  • 优化Input Checkbox与Label文本对齐的方法
    本文探讨了在网页设计中,如何有效解决input checkbox与label文字不对齐的问题。通过具体的代码实例和解决方案,帮助开发者实现更加美观的用户界面。 ... [详细]
  • 在使用高德地图内置导航功能时遇到AMapNavi组件出现空指针异常,经过多次排查发现问题是由于so库的兼容性引起的。本文将详细介绍如何通过调整项目配置来解决这一问题。 ... [详细]
  • 深入解析IGMP各版本特性及其演进
    本文详细探讨了Internet组管理协议(IGMP)的不同版本,包括IGMPv1的基础功能、IGMPv2的增强特性和IGMPv3的重要改进。特别分析了IGMPv3如何支持特定源组播(SSM)模型,并介绍了各版本之间的主要差异。 ... [详细]
  • 初探SoloPi:一款强大的Android自动化测试工具
    SoloPi是一款由支付宝开发的无线化、非侵入式且无需Root的Android自动化测试工具。它提供了录制回放、性能测试和一机多控三大核心功能,极大地提高了测试开发人员的工作效率。 ... [详细]
  • 前言无论是对于刚入行工作还是已经工作几年的java开发者来说,面试求职始终是你需要直面的一件事情。首先梳理自己的知识体系,针对性准备,会有事半功倍的效果。我们往往会把重点放在技术上 ... [详细]
  • YB02 防水车载GPS追踪器
    YB02防水车载GPS追踪器由Yuebiz科技有限公司设计生产,适用于车辆防盗、车队管理和实时追踪等多种场合。 ... [详细]
  • Java与JSON互转:实现JSON到Java对象及Java对象到JSON的转换
    本文详细介绍了如何在Java中实现JSON数据与Java对象之间的相互转换,包括代码示例和常见问题解决方法。 ... [详细]
  • Ubuntu GamePack:专为游戏爱好者打造的Linux发行版
    随着Linux系统在游戏领域的应用越来越广泛,许多Linux用户开始寻求在自己的系统上畅玩游戏的方法。UALinux,一家致力于推广GNU/Linux使用的乌克兰公司,推出了基于Ubuntu 16.04的Ubuntu GamePack,旨在为Linux用户提供一个游戏友好型的操作环境。 ... [详细]
  • MySQL锁机制详解
    本文深入探讨了MySQL中的锁机制,包括表级锁、行级锁以及元数据锁,通过实例详细解释了各种锁的工作原理及其应用场景。同时,文章还介绍了如何通过锁来优化数据库性能,避免常见的并发问题。 ... [详细]
  • 本文探讨了如何利用SqlDependency执行复杂的SQL查询,并确保在多线程环境下的安全性与效率。 ... [详细]
  • Python数据类型6 字典
    字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包 ... [详细]
  • 本文详细介绍了ActivityManagerService (AMS) 的工作原理及其在Android系统中的重要角色。AMS作为system_server进程的一部分,在系统启动时加载,负责管理和协调应用程序中的Activity和服务(Service)。文章将通过具体的接口图和通信流程,帮助读者更好地理解AMS的工作机制。 ... [详细]
  • EasyMock实战指南
    本文介绍了如何使用EasyMock进行单元测试,特别是当测试对象的合作者依赖于外部资源或尚未实现时。通过具体的示例,展示了EasyMock在模拟对象行为方面的强大功能。 ... [详细]
author-avatar
PHP培训师
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有