Android多语言适配繁体中文
Android多语言适配一般默认是values/drawable目录下的文件是英文语言的资源,如果在中文下使用不同的资源则需要新建values-zh/drawable-zh-xxxdpi这样,res目录下的命名规则是drawable-语言-国家-xxxdpi,在没有特定国家的资源会先找语言相关的目录。但是中文有点特别!这也是一个坑,按常规思维drawable-zh应该是简体中文/繁体中文共有的资源,就是如果没有drawable-zh-rTw或drawable-zh-rHK的资源的话当切到繁体中文时会去drawable-zh查找资源,这样想是大错特错,实际的结果是没有繁体资源时系统会去默认的目录下查找,也就是在drawable或drawable-xxxdpi这些目录找,这个是android的bug还是故意认为HK和TW不是我大中华的?
废话不多话说,实际开发过程中会有这样的需求,就是希望所有的中文不管是繁体还是简体都是共用资源的,根据上面说的规则,如果不分别在zh-rTW和zh-rHK都放入资源的话是不可能做到了,那如果还是想省点资源怎么办呢?下面就是说说图片资源如何做到这点,这里关键要了解android资源的实现,android资源像ImageView查找资源是通过Resources来操作的,来看ImageView查找图片时的关键函数:
private void resolveUri() { if (mDrawable != null) { return; } if (getResources() == null) { return; } Drawable d = null; if (mResource != 0) { try { // 关键的地方 d = mContext.getDrawable(mResource); } catch (Exception e) { Log.w(LOG_TAG, "Unable to find resource: " + mResource, e); // Don't try again. mResource = 0; } } else if (mUri != null) { d = getDrawableFromUri(mUri); if (d == null) { Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri); // Don't try again. mUri = null; } } else { return; }} updateDrawable(d); }
可以知道关键的地方是能过context.getDrawable来拿到的,如果我们能重写这个函数是不是就可以搞定了?答案是不能,因为这个函数是final不能被重写的,实现如下:
public final Drawable getDrawable(@DrawableRes int id) { return getResources().getDrawable(id, getTheme());}
能怎么办呢,答案就从上面getDrawable函数的实现找到,getDrawable是能过getResources().getDrawable来实现的,如果能重写getResources,在这里判断是否是繁体,如果是则去zh目录下查找资源,来看getResources的实现:
// Context.javapublic abstract Resources getResources();
看到这里,你应该知道这个思路是可以的!于是按思中路实现,首先判断是否是繁体,然后去默认中文目录下查找
第一步:
判断是用什么语言和国家可以用resources获取config
Locale locale = context.getResources().getConfiguration().locale;if (locale.getLanguage().equals("zh") && !locale.getCountry().equals("CN")) {// 繁体中文}
第二步:
去中文目录查找,首先得有一个中文的resources,当前activity的resources是繁体的,是不能直接调用的,实现方法如下:
private static void updateResource(Resources resource, Locale l) { Configuration config = resource.getConfiguration(); config.locale = l; resource.updateConfiguration(config, null);}private static Resources getApplicationResource(PackageManager pm, String pkgName, Locale l) { Resources resourceForApplication = null; try { resourceForApplication = pm.getResourcesForApplication(pkgName); updateResource(resourceForApplication, l); } catch (PackageManager.NameNotFoundException e) { } return resourceForApplication;}//得到简体中文的resources,由于简体中文没有资源,所以会去默认的中文下去找Resources resources = getApplicationResource(context.getApplicationContext().getPackageManager(), context.getPackageName(), new Locale("zh", "CN"));
综合起来是重写Activity的getResources:
@Overridepublic Resources getResources() { Locale locale = context.getResources().getConfiguration().locale; if (locale.getLanguage().equals("zh") && !locale.getCountry().equals("CN")) { // 繁体中文 Resources resources = getApplicationResource(context.getApplicationContext().getPackageManager(), context.getPackageName(), new Locale("zh", "CN")); if (resources != null) { return resources; } } return super.getResources();}
这样就实现了所有中文上都共用一套资源!上面的示例在xml中指定资源或者在代码里getDrawable可以这么使用,如果是用第三方图片加载库怎么实现?这里展示一下ImageLoader的实现:
ImageLoader加载资源是默认是通过BaseImageLoader去加载的,加载时会调用BaseDownloader去获取资源,我们只要自定义Downloader就可以了:
public class NotePaperImageDownloader extends BaseImageDownloader { // 繁体中文时用的resources Resources mResources; public NotePaperImageDownloader(Context context) { super(context); } public NotePaperImageDownloader(Context context, int connectTimeout, int readTimeout) { super(context, connectTimeout, readTimeout); } @Override protected InputStream getStreamFromDrawable(String imageUri, Object extra) { Locale locale = context.getResources().getConfiguration().locale; if (locale.getLanguage().equals("zh") && !locale.getCountry().equals("CN")) { // 繁体中文,使用简体中文的资源进行加载,否则在没有指定繁体资源时默认会去英文下找,会不会去drawable-zh-xx去找 if (mResources == null) { Resources resources = getApplicationResource(context.getApplicationContext().getPackageManager(), context.getPackageName(), new Locale("zh", "CN")); if (resources == null) { return super.getStreamFromDrawable(imageUri, extra); } mResources = resources; } String drawableIdString = Scheme.DRAWABLE.crop(imageUri); int drawableId = Integer.parseInt(drawableIdString); return mResources.openRawResource(drawableId); } else { return super.getStreamFromDrawable(imageUri, extra); } }}
总结:
关于android资源的加载,只要熟悉资源加载框架context/resources/assetmanger几个关键的类就可以做很多事。
更多相关文章
- 理解 ViewStub 原理
- Android(安卓)深入理解Loader机制 让APP轻装上阵
- Android:资源 id 及资源 id 的动态获取
- 安卓系统的启动流程
- android TextView设置中文字体加粗实现方法
- Android(安卓)项目中文件夹作用(res文件夹详细介绍)
- android中URI简介
- Android中多媒体处理
- android全平台编译libjpeg-turbo并基于ANativeWindow加载JPEG图