来源《Android/OPhone开发完全讲义》
本文主要介绍Android SDK中的资源,国际化和资源自适应技术。通过国际化和资源自适应技术,使应用程序可以根据不同的语言环境显示不同的界面,风格,也可以根据手机的特性做 出相应的调整。开发者可以根据这些内容编写更有弹性的应用,并可以大大减少编码的工作量。
1、Android中的资源
资源是Android应用程序中重要的组成部分。在应用程序中会使用到字符串、菜单、图像、声音、视频等内容,这些可以统称为资源。通过将这些资源放到apk文件中与Android应用程序一同发布。如果资源文件很大,也可以将资源作为外部文件是用。
1.1、Android如何存储资源
资源大多保存在res目录中。例如字符串、颜色等资源以键值对(key-value)保存在res/values目录中的XML文件中;菜单资源保存在 res/menu目录中。ADT在生成apk文件时,这些目录中的资源文件会被编译到apk文件中,但res/raw目录中的资源不会被编译。在程序运行 时,可以通过InputStream来读取res/raw目录中的资源。
当资源文件很大时,编译后的apk文件也会很大,可能造成系统装载资源文件缓慢,从而影响应用程序的性能。这时可以将资源文件作为外部文件单独发布。
1.2、资源的种类
目录 | 资源类型 | 描述 |
res/values |
XML | 保存字符串、颜色、尺寸、类型、主题等资源,可以是任意文件名。对于字符串,颜色尺寸等信息采用key-value形式表示,对于类型,主题等资源,采用其它形式表示。 |
res/layout | XML | 保存布局信息。一个资源文件表示一个View或者ViewGroup的布局。 |
res/menu | XML | 保存菜单资源。一个资源文件表示一个菜单(包括子菜单)。 |
res/anim | XML | 保存与动画相关的信息。可以定义帧(frame)动画和补间(tween)动画。 |
res/xml | XML | 在该目录中的文件可以是任意类型的XML文件,这些XML文件可以在运行的时候被读取。 |
res/raw | 任意类型 | 在该目录中的文件不会被编译。在该目录中可以放置任意类型的文件,例如,文档,音频,视频等。 |
res/drawable | 图像 | 该目录中的文件可以是多种格式的图像文件,例如:bmp,png,gif,jpg等。在该目录中的图像不需要分辨率非常高,aapt工具会优化这个目录中的图像文件。如果想要按字流读取该目录中的图像文件,需要将图片放到res/raw目录中。 |
assets | 任意类型 | 该目录中的资源与res/raw中的资源一样,也不会被编译。但不同的是该目录中的资源不会生成资源ID。 |
1.3、资源文件的命名
每一个资源文件或资源文件中的key-value对都会在ADT自动生成R类中找到相应的ID。其中资源文件名或key-value对中的key就是R类中的Java变量名。因此,资源文件名和key的命名首先要符合Java变量的命名规范。虽然Java变量名支持中文,但是资源文件和key不能使用中文。
除了资源文件和key本身的命名规范外,多个资源文件和key也要遵循唯一的原则。也就是说,同类资源的文件名或key不能重复。
虽然操作系统会禁止同一个目录出现两个同名文件的情况发生,但由于ADT在生成ID时不考虑资源文件的扩展名,因此,在res/drawable、res/raw等目录中不能存在文件名相同、扩展名不同的资源文件。
2、定义和使用资源
在Android SDK中不仅提供了大量的系统资源,而且还允许开发人员定制自己的资源。
2.1、使用系统资源
在Android SDK中提供大量的系统资源,这些资源放在res目录中。可以在<Android SDK安装目录>\platforms\android-1.5\data\res目录中找到这些资源。
代码引用格式:
android.R.resourceType.resourceId
其中resourceType表示资源类型,例如,string,drawable,color等。resourceId表示资源ID。
XML引用格式:
@android:resourceType/resourceId
2.2、字符串
字符串资源存放在res/string目录的XML文件中,定义格式是:<string name="key">value</string>
示例:
<string name="application_name">应用名称</string>
2.3、数组
字符串数据资源用<string-array>标签定义,整数数组资源用<integer-array>标签定义。下面是array.xml文件示例:
<resources> <string-array name="string-value"> <item>string a</item> <item>string b</item> </string-array> <integer-array name="integer-value"> <item>100</item> <item>200</item> </integer-array> </resources>
读取时的代码示例:
String[] stringValues = getResources().getStringArray(R.array.string-value); int[] integerValues = getResources().getIntArray(R.array.integer-value);
2.4、颜色资源
Android允许将颜色值作为资源保存在资源文件中。保存在资源文件中的颜色值以“#”开头,并支持如下四种表示方式:
其中R、G、B表示三原色,即红、绿、蓝,A表示通明度,即Alpha值。
颜色值定义在res/values目录的资源文件中。示例color.xml:
<resources> <color name="red_color">#F00</color> <color name="blue_color">#0000FF</color> <color name="green_color">#5000FF00</color> <color name="white_color">#5FFF</color> </resources
2.5、尺寸资源
尺寸资源是一系列的浮点数组成的资源,这些资源在res/values目录的资源文件中定义,<dimen>标签用来定义尺寸资源。示例dimension.xml文件:
<resources> <dimen name="size_px">50px</dimen> <dimen name="size_in">1.5in</dimen> <dimen name="size_sp">50sp</dimen> </resources>
Android支持的六种度量单位:
2.6、类型资源
虽然可以在XML布局文件中灵活的设置组件的属性,但如果有很多组件都需要设置同一值,那么每个组件都设置各自的属性值就比较麻烦。而类型资源可以解决这个问题。
类型资源实际上就是将需要设置相同的值的属性提取出来放在单独的地方,然后在每一个需要设置这些属性的组件中引用这些类型。这种效果有些类似于面向对象中的方法。将公共的部分提取出来,然后在多个方法中调用这个执行公共代码的方法。
类型在res/values目录中定义。每一个<style>标签表示一个类型,该标签有一个name属性,表示类型名,在类型中每一个属性使用<item>表示。类型之间可以继承,通过<style>标签的parent属性指定父类型的资源ID。引用类型的语法是:@style/resourceId。下面的代码styles.xml定义了三个类型,并设置了相应的继承关系:
<resources> <style name="style1"> <item name="android:textSize">20sp</itme> <item name="android:textColor">#FFFF00</itme> </style> <style name="style2" parent="@style/style1"> <item name="android:gravity">center_horizontal</itme> </style> <style name="style3" parent="@style/style2"> <item name="android:gravity">right</itme> <item name="android:textColor">#FF0000</itme> </style> </resources>
或者可以采用下面的形式标明继承关系:
<resources> <style name="style1"> <item name="android:textSize">20sp</itme> <item name="android:textColor">#FFFF00</itme> </style> <style name="style1.style2"> <item name="android:gravity">center_horizontal</itme> </style> <style name="style2.style3"> <item name="android:gravity">right</itme> <item name="android:textColor">#FF0000</itme> </style> </resources>
2.7、主题资源
主题也是类型,只是这种类型只能使用于<activity>和<application>标签。其中<activity>用于定义Activity,该标签是<application>的子标签。如果在<application>标签中使用主题,那么所有在<application>标签中的<activity>都会继承这个主题。在<activity>中使用主题可以覆盖<application>的主题。
2.8、绘画资源
在Android应用程序中经常使用到很多图像,这些图像资源保存在res/drawable目录下。Android支持很多常用的图片格式,例如jpg,png,bmp,gif(不包括动画gif)。
Android SDK还支持一种绘制颜色的Drawable资源,这种资源需要在res/values目录中的资源文件中配置。配置文件和颜色资源类似,只是要使用<drawable>标签,如下:
<drawable name="blue">#0000FF</drawable> <drawable name="yellow">#FFFF00</drawable>
XML布局文件中引用方法:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="200dp" android:textColor="@drawable/yellow" android:background="@drawable/blue" />
代码中引用方法:
Drawable drawable = getResources().getDrawable(R.drawable.yellow);
2.9、动画资源
Android SDK支持两种2D动画:帧(Frame)动画和补间(Tween)动画。这两种动画都由动画文件控制,这些动画文件必须放在res/anim目录中。其中涉及到的图像文件仍然要放在res/drawable目录中。动画文件及其相关的图像文件统称为动画资源。
帧动画由若干幅图组成,通过设置每幅图的停留时间,可以控制播放的快慢。补间动画首先要设置目标(可以是图像、组件等元素)的开始状态和结束状态,以及动画效果等参数,然后由系统自动生成中间状态的目标形状和位置。
2.10、菜单资源
菜单除了可以使用Java代码定义外,还可以使用XML文件来定义。这些定义菜单的XML文件称为菜单资源。菜单资源必须放在res/menu目录中。
菜单资源文件必须使用<menu>标签作为根节点。除了<menu>标签外,还有另外的两个标签用于设置菜单和分组,这两个标签是<item>和<group>。
<menu>标签没有任何属性,但可以嵌套在<item>标签中,表示一个子菜单。<item>标签中不能再嵌入<item>标签,否则系统会忽略嵌入的<item>标签(不会抛出异常)。<item>标签的属性含义如下:
<group>标签的属性含义如下:
下面是一个菜单资源文件的例子options_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/mnuFestival" android:title="节日" android:icon="@android:drawable/ic_menu_agenda"> </item> <group android:id="@+id/mnuFunction"> <item android:id="@+id/mnuEdit" android:title="编辑" android:icon="@android:drawable/ic_menu_edit"> </item> <item android:id="@+id/mnuDelete" android:title="删除" android:icon="@android:drawable/ic_menu_delete"> </item> <item android:id="@+id/mnuFinish" android:title="完成" android:icon="@android:drawable/ic_menu_directions"> </item> </group> <item android:id="@+id/mnuOthers" android:title="其它功能"> <menu> <group android:checkableBehavior="single"> <item android:id="@+id/mnuDiary" android:title="日记" android:menuCategory="system" android:checked="true"> </item> <item android:id="@+id/mnuAudio" android:title="音频" android:orderInCategory="2"> </item> <item android:id="@+id/mnuVideo" android:title="视频" android:orderInCategory="3"> </item> </group> </menu> </item> </menu>
在options_menu.xml资源文件中定义了一个选项菜单和一个子菜单。为了显示选项菜单,需要在onCreateOptionsMenu事件方法中装载这个菜单资源文件,如下:
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.options_menu, menu); menu.findItem(R.id.mnuEdit).setOnMenuItemClickListener(this); menu.getItem(4).getSubMenu().setHeaderIcon(R.drawable.ic_launcher); return true; }
除了选项菜单和子菜单,上下文菜单也可以使用菜单资源文件定义。示例:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/mnuEdit" android:title="编辑"> </item> <item android:id="@+id/mnuDelete" android:title="删除"> </item> <item android:id="@+id/mnuFinish" android:title="完成"> </item> </menu>
在onCreateContextMenu事件方法中显示上下文菜单,如下:
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.context_menu, menu); super.onCreateContextMenu(menu, v, menuInfo); }
最后注册到对应的组件,示例:
EditText editText = (EditText) findViewById(R.id.editText1); registerForContextMenu(editText);
2.11、布局资源
Android应用程序有两种方式生成组件:XML布局文件和Java代码。所有的XML布局文件必须保存在res/layout目录中。假设在res/layout目录中有一个名为test.xml的布局文件,可以使用R.layout.test来引用这个XML布局文件。
2.12、属性资源
Android允许开发者定义自己的组件属性,在此不再赘述。
2.13、XML资源
XML资源实际上就是XML格式的文本文件,这些文件保存在res/xml目录中。可以通过Resources.getXML方法获得处理XML文件的XmlResourceParser对象。关于XmlResourceParser解析XML文件的过程,在此不再赘述。
2.14、RAW资源
放在res/raw目录中的资源文件称为RAW资源。该目录中的任何文件都不会被编译。可以通过Resources.openRawResource方法获得读取指定文件的InputStream对象,代码如下:
InputStream is = getResources().openRawResource(R.raw.resourceId);
2.15、Assets资源
assets资源与前面介绍的资源不一样,该资源所在目录不是res目录,而是和res平级的assets目录。也就是所有放在assets目录中的资源文件不会生成资源ID。因此,在读取资源文件时,需要直接使用资源文件名称。
假如读取assets目录中的test.txt文件,那么可以用如下代码读取:
TextView textView = new TextView(this); InputStream inputStream = null; try { inputStream = getAssets().open("test.txt"); byte[] buffer = new byte[1024]; int count = inputStream.read(buffer); String string = new String(buffer, 0, count); textView.setText(string); } catch (Exception e) { e.printStackTrace(); if (inputStream != null) { try { inputStream.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
3、国际化和资源自适应
由于分布在不同国家的用户的语言和习惯不同,在全球发布软件时必须考虑要满足不同国家和地区用户的需求。这种应用程序的界面语言和风格随着Android系统当前的语言环境变化而变化的技术称为国际化。除了国际化,还需要考虑资源的自适应性。由于手机的分辨率、屏幕方向等环境不同,造成在环境A中的资源可能在环境B中无法正常工作,或出现界面混乱的情况。虽然可以采用相应的布局技术进行处理,但随着手机运行环境的不断增多,情况变得越来越复杂。
3.1、对资源进行国际化
通过Android SDK来实现国际化功能几乎不需要什么成本,只需要将界面文字翻译成不同语言的文字,然后将相应的资源文件放到各种语言特定国际化资源目录即可。
对于字符串国际化,实际就是为应用程序提供不同语言的字符串。当程序在运行时会检测当前语言环境,再根据语言环境决定读取哪种语言的字符串资源。检测语言环境的任务由Android系统负责完成,开发人员要做的是为保存各种语言的字符串资源建立国际化目录,然后将相应的资源文件放到这些目录中。国际化目录的规则如下:
资源目录+国际化配置选项
其中资源目录指res目录中的子目录,例如values、layout等。国际化配置选项包含很多部分,中间用“-”分隔。例如要实现不同语言和地区的国际化,这些配置选项包括语言代号和地区代号。表示中文和中国的配置选项是zh-rCN;表示英文和美国的配置选项是en-rUS。其中zh和en表示中文和英文;CN和US表示中国和美国;前面的r是必须的,为了区分地区部分。不能单独指定地区,但可以单独指定语言。
语言配置选项:http://www.loc.gov/standards/iso639-2/php/code_list.php
3.2、Locale与国际化
除了可以使用资源目录处理国际化问题外,还可以使用Local对象获得当前的语言环境,然后根据语言环境决定读取哪个资源文件中的资源。使用这种方式可以将资源文件放在assets目录中。
获得国家和语言的代码如下:
国家: Locale.getDefault().getCountry(); 语言: Locale.getDefault().getLanguage();
3.3、常用的资源配置
Android SDK处了支持语言和地区配置选项外,还支持很多其它的配置选项。例如,与分辨率相关的配置选项、Android SDK版本的配置等。常用的资源配置如下:
1、屏幕尺寸
该配置有三个选项:small、normal、large。描述如下:
2、Wider/taller屏幕
该配置分成2个选项:long和notlong。这个配置选项实际上表示当前的屏幕是否比传统的屏幕更高、更宽。系统是根据屏幕的直观比例决定手机屏幕属于哪个选项值。例如,QVGA、HVGA和VGA的选项是notlong,而WQVGA、WVGA和FWVGA是long。要注意的是,long可能意味着更宽或更高,着要依赖屏幕的方向而定。
3、屏幕方向
该配置分成3个选项:port、land和square。其中square目前没有被使用;port表示纵横比大于1的方向;land表示纵横比小于1的方向。纵横比就是手机高度和宽度之比。
4、屏幕像素密度
该配置分为4个选项:ldpi、mdpi、hdpi、nodpi。其中ldpi表示低密度(120dpi);mdpi表示传统的HVGA屏幕的密度(中等密度,160dpi);hdpi表示高密度(240dpi)。nodpi密度用于位图资源,以防止他们为了匹配设备的屏幕密度而被拉伸。
5、屏幕分辨率
该配置没有具体的选项,需要根据实际的屏幕分辨率来设置。例如:分辨率为320X480的屏幕要设为480X320,480X640的屏幕要设为640X480.要注意的是,较大的值要在前面。中间要用“X”,而不能用“*”。
6、SDK版本
Android SDK1.0的配置选项是v1;Android SDK1.1的配置选项是v2;Android SDK1.5的配置选项是v3;以此类推。