4.1 Android应用程序中的资源
任何类型的程序都需要使用资源,Android应用程序也不例外。Android应用程序使用的资源有很多都被封装在apk文件中,并随apk文件一起发布。本节将介绍这些资源如何封装在apk文件中,以及使用这些资源的基本方法。
4.1.1 资源存放在哪里
既然要将资源封装在apk文件中,那么这些资源一定是放在Android工程的某处。在第3章实现的应用程序中可以看到,在Android工程中有一个res目录。在该目录下有若干个子目录,例如,drawable-hdpi、layout、menu、values等,这些子目录有很多都是本地化的资源目录,也就是说这些资源目录中的资源只有Android应用程序运行在特定的环境中才会使用。例如,drawable-hdpi用于存放图像资源,该资源目录仅针对高密度的屏幕才会使用。而真正的资源目录是前面的drawable。如果不考虑本地化,可以直接在res目录中建立一个drawable目录。该目录的图像资源在其他本地化图像资源目录中没有符合要求的图像资源的情况下会使用res/drawable目录中的图像资源。
其他的资源目录也是一样,例如values是默认的值资源目录,也可以为其建立本地化值资源目录,例如,values-hdpi。Android系统会首先考虑某一类型的资源是否有本地化资源目录,并且本地化资源目录中是否有符合要求的资源,然后才会考虑默认的资源目录。也就是说系统会首先确认当前屏幕密度是否为高密度,如果是高密度屏幕,会首先到values-hdpi目录寻找资源文件,如果未找到,才会到values目录中继续寻找。关于Android资源文件的详细内容后面的章节会专门介绍。读者从本节只要了解到Android应用程序有一个res资源目录,该目录存储了一些预定类型的资源。
4.1.2 资源的基本使用方法
Android支持3种文件格式的资源:XML文件、图像以及二进制格式(例如,音频、视频文件),这些资源文件分别放在res目录的不同子目录中。在编译Android应用程序的同时,系统会使用一个资源文件编译程序(aapt)对这些资源文件进行编译。这些资源主要包括图像资源(/res/drawable)、动画资源(res/anim)、布局资源(res/layout)、菜单资源(res/menu)等。
Android会为每一种资源在R类中生成一个唯一的ID,这个ID是int类型的变量。在一般情况下,开发人员并不需要管这个类,更不需要修改这个类,只需要直接使用R类中的ID即可。为了更好地理解使用资源的过程,先看一下第3章的例子中生成的R类的源代码。
package mobile.android.show.datetime;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int ic_action_search=0x7f020000;
public static final int ic_launcher=0x7f020001;
}
public static final class id {
public static final int btnShowDate=0x7f070000;
public static final int btnShowTime=0x7f070001;
public static final int menu_settings=0x7f070002;
}
public static final class layout {
public static final int activity_datetime=0x7f030000;
}
public static final class menu {
public static final int activity_datetime=0x7f060000;
}
public static final class string {
public static final int app_name=0x7f040000;
public static final int hello_world=0x7f040001;
public static final int menu_settings=0x7f040002;
public static final int title_activity_datetime=0x7f040003;
}
public static final class style {
public static final int AppTheme=0x7f050000;
}
}
从R类中很容易看出,ADT为res目录中每一个子目录或标签(例如,res/values/strings.xml中的<string>标签)都生成了一个静态的子类,不仅如此,还为XML布局文件中的每一个指定id属性的控件生成了唯一的ID,并封装在id子类中。这就意味着在Android应用程序中可以通过ID使用这些控件。
注意
R类虽然也属于mobile.android.show.datetime包,但由于R类是自动生成的,为了将R类与其他的Java类区分开,将R类放在gen目录中。
我们可以使用如下的两种方法引用资源。
使用Java代码引用资源。
在XML文件中引用资源。
下面的代码通过Java代码获取btnShowDate按钮对象。
Button btnShowDate = (Button) findViewById(R.id.btnShowDate);
下面的代码在定义Activity时引用了字符串资源。
<activity
android:name=".DatetimeActivity"
android:label="@string/title_activity_datetime" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
从上面的代码可以看出,在Java代码中直接引用了R.id.btnShowDate这个ID值,当然,直接使用0x7f070000也可以,不过为了使程序更易读和维护,一般会直接使用在R的内嵌类中定义的变量名。在定义Activity时android:label属性值使用@string/resource_id的形式引用字符串资源,例如,@string/title_activity_datetime。
Android SDK中的很多方法都支持直接使用ID值来引用资源,例如,android.app.Activity.setTitle方法除了支持以字符串形式设置Activity的标题外,还支持以字符串资源ID的形式设置Activity的标签。例如,下面的代码使用字符串资源重新设置了Activity的标题。
setTitle(R.string.hello);