想做出一款出色的App,仅仅编写Java代码还不够。在代码中调用资源(Resources ),如位图(bitmaps)、布局资源( layout definitions)、UI中需要展示的字符串资源(user interface strings)、动画资源(animation instructions)等,可以让您的App更加出色。
本文将介绍Android中各种类型的资源、以及获取资源的方式,如需访问官方原文,您可以点击这个链接:《App Resources》。
在本小节中,将介绍可为App提供的资源类型、如何存储这些资源,以及如何为特定的设备配置替代的资源 等。
您应当将字符串、图片等资源从Java代码中剥离出来,这样方便独立地管理。另外,通过建立带有特定后缀名的资源文件夹,系统可以自动将这些文件夹中的资源设置到符合要求的设备上(如分辨率、屏幕尺寸 等)。
所有的资源都存放在res/
目录下,下面是一个演示MyProject的工程结构:
MyProject/
src/
MyActivity.java
res/
drawable/
graphic.png
layout/
main.xml
info.xml
mipmap/
icon.png
values/
strings.xml
需要注意的是,mipmap/
目录下应存放的是图标资源,而drawable/
目录下存放的是普通的图片资源,下面的表格介绍了res/
目录下可以存放的子目录名称以及它们可以存放的资源类型。
子目录名称(Directory) | 资源类型(Resource Type) |
---|---|
animator/ |
定义属性动画的XML文件 |
anim/ |
定义补间动画的XML文件 |
color/ |
定义颜色状态列表的XML文件 |
drawable/ |
各种格式的位图文件(.png, .9.png, .jpg, .gif),编译为以下 Drawable 资源子类型的 XML 文件:位图文件(Bitmap files)、Nine-Patches图片、State lists、Shapes、Animation drawables、Other drawables |
mipmap/ |
各种分辨率的启动图标资源 |
layout/ |
定义布局的XML文件 |
menu/ |
定义菜单资源的XML文件。如Options Menu、Context Menu、或Sub Menu 等 |
raw/ |
以原始格式保存的任意文件。使用InputStream 打开这些资源,调用Resources.openRawResource() 方法传入资源id,即:R.raw.filename .如需访问原始文件名和文件层次结构,则可以考虑将某些资源保存在 assets/ 目录下,保存在该目录下文件的文件名不会映射到R类中,即不会生成资源ID,如需获取资源,需使用AssetManager 类。 |
values/ |
包含字符串、整型数和颜色等简单值的 XML 文件,需要使用<resources> 作为根标签生命不同类型的资源,如子标签为<string> 表示字符串资源、子标签<color> 表示颜色资源,映射到R类分别为R.string 、R.color 。为了区分这些不同标签的文件,应在values/ 下建立不同的XML文件,如arrays.xml 中为数组资源,colors.xml 中为颜色资源,dimens.xml 中为尺寸资源,strings.xml 中为字符串资源,styles.xml 中为样式资源 |
xml/ |
任何XML格式的文件,可以在程序运行时调用Resources.getXML() 方法获取到。 |
!请注意:请不要在res/
的根路径下直接存放资源文件,否则会引发异常。
在上表中定义的子目录名称都是缺省目录名称,也就是说,定义在这些目录名称下的资源不一定是程序需要加载的“上佳”资源,而是没有最佳资源时加载的“下策”资源。那么什么是“最佳”资源?Android设备千差万别,有的屏幕大、有的分辨率高:若为一个高分辨率的大屏设备加载缺省的图片资源,一定有未被利用的屏幕空间;即便是型号相同的设备,不同国家的用户可能需要设置不同的语言:若为一个设置了“中文”主题语言的设备加载“英文”的缺省资源,显然不太合适。为不同类型的设备(屏幕、语言、分辨率 等等)专门提供不同的资源,称为“最佳”资源。
几乎所有的app都会为适配各式各样的设备而提供相应的资源,比如,您可能需要为不同屏幕密度的设备提供不同的drawable资源、为设置了不同系统语言的设备提供不同的string资源。在app运行时,程序会自动检测当前设备的配置信息,并为其加载合适的资源。
提供不同种类资源的方式如下:
在res/
目录下创建一个类似于<resources_name>-<config_qualifier>
格式的子目录:
其中<resources_name>
为资源的缺省子目录名,如上一小节的表格所示;
<qualifier>
是一个限定符,表示为满足该限定符条件的设备加载资源。如下表所示。
您可以同时使用多个<qualifier>
限定符后缀,限定符之间用英文半角的破折号连接,即 “ - ”。这些限定符需要按照下面表格的顺序排列,否则该资源文件夹将被忽略。
res/
drawable/
icon.png
background.png
drawable-hdpi/
icon.png
background.png
其中限定符hdpi
表示该资源文件夹中的文件将被加载至具有高分辨率屏幕的设备上。在这些不同的drawable文件夹下,图片具有不同的分辨率,然而它们的名字相同。这样就可以使用一致的ID名将该资源引用至Java代码中。
下表罗列了您可以添加的限定符名称,再一次强调,如有多个限定符,那么需要按照下表的顺序排列。
资源类型(Configuration) | 限定符举例(Qualifier Values) | 描述(Description) |
---|---|---|
国家移动代码 和 网络移动代码(MCC and MNC) | 举例:mcc310、mcc310-mnc004、mcc208-mnc00 等 |
MCC=The mobile country code ,国家移动代码。后面可以有选择性地跟随MNC=mobile network code,即移动网络代码。例如,mcc310 代表美国的国家移动代码(MCC),而mcc310-mnc004 代表美国的Verizon运营商;而mcc208-mnc00 代表法国的Orange运营商。如果设备使用的是GSM网络,那么MCC 和 MNC的代码可以在SIM卡上找到。 |
语言和地区(Language and region) | en、fr、en-rUS、fr-rFR、fr-rCA 等 |
其中两个小写英文字母表示语言代码,具体可参照ISO 639-1 标准;由小写字母“r”开头、两个大写字母紧随其后的限定符表示地区码,地区码是一个可选限定符,您可以有选择地加入,但是地区码不能脱离语言代码而独立存在,具体可参照ISO 3166-1-alpha-2 标准。当用户改变设备的系统语言时,系统加载的语言资源也应当随之改变,具体可以参照我的后续翻译,或者直接点击这个链接《Handling Runtime Changes》 。 |
布局方向(Layout Direction) | ldrtl 、ldltr |
ldrtl 表示布局的方式为从右向左(layout-direction-right-to-left),而ldltr 表示从左向右(layout-direction-left-to-right),这也是默认值。这个限定符可以添加到任何资源名后,如 layout、drawable, 或 values 等。!请注意:为了添加从右至左的布局资源,需要将supportsRtl 属性设置为true,并且将targetSdkVersion 设置为17或以上。 |
最小宽度(smallestWidth) | 通式形式:sw<N>dp ;比如:sw320dp 、sw600dp 、sw720dp 等 |
表示屏幕的最小宽度。比如某个布局资源需要加载到至少600dp宽的设备屏幕上,那么您只需要在res/layout-sw600dp/ 目录下添加该布局文件即可,需要注意的是,屏幕最小宽度(smallestWidth )是一个设备的固定属性,它不会随着用户所持设备的方向而改变( The smallestWidth is a fixed screen size characteristic of the device; the device’s smallestWidth does not change when the screen’s orientation changes)。通过android:requiresSmallestWidthDp 属性可以指定程序支持的最小屏幕宽度。通过smallestScreenWidthDp 属性可以查询当前设备的最小宽度。 |
可用宽度(Available width) | 通式:w<N>dp ;比如:w720dp 、w1024dp 等 |
指定一个可用的最小宽度。这个属性会随着屏幕的横竖变化而变化。通过screenWidthDp ,可以查询当前的属性值。 |
可用高度(Available height) | 通式:h<N>dp ;比如:h720dp 、h1024dp 等 |
与可用宽度类似。使用screenHeightDp 属性可以查询当前的设备的可用宽度。 |
屏幕大小(Screen size) | small 、normal 、large 、xlarge |
一般情况下使用xlarge ,表示屏幕尺寸接近720dpx960dp。!请注意:如果您的限定符尺寸超过了屏幕的实际尺寸,程序将崩溃,如您的资源都放在了large 文件夹下,而设备的屏幕只有normal 大小。 |
屏幕纵横比(Screen aspect) | long 、notlong |
long :宽屏,如 WQVGA、WVGA、FWVGA;notlong :非宽屏,如 QVGA、HVGA 和 VGA |
屏幕形状(Round screen) | round 、notround |
round :圆形屏幕,如手表等设备;notround :矩形屏幕,如手机或平板.该限定符于API23引入,通过isScreenRound() 可以判断设备的屏幕形状是否为圆形。 |
屏幕方向(Screen orientation) | port 、land |
port :屏幕为竖直方向;land :屏幕为水平方向 |
UI 模式(UI mode) | car 、desk 、television 、appliance 、watch |
car :车载系统的UI;desk :桌面系统的UI;television :电视的UI;appliance 无屏幕的设备;watch :手表设备。 |
夜间模式(Night mode) | night 、notnight |
night :晚间;notnight :白天。 |
屏幕像素密度(Screen pixel density (dpi)) | ldpi 、mdpi 、hdpi 、xhdpi 、xxhdpi 、xxxhdpi 、nodpi 、tvdpi 、anydpi |
主流:xhdpi :接近320dpi;xxhdpi :接近480dpi;xxxhdpi :只针对启动图标,接近640dpi。 |
触屏类型(Touchscreen type) | notouch 、finger |
notouch :设备无触屏;finger :设备包含触摸屏。 |
键盘可用性(Keyboard availability) | keysexposed 、keyshidden 、keyssoft |
keysexposed :设备具有可用的键盘;keyshidden :设备具有可用的硬键盘,但它处于隐藏状态,且设备没有启用软键盘;keyssoft :设备已经启用软键盘(无论是否可见)。 |
主要文本输入法(Primary text input method) | nokeys 、qwerty 、12key |
nokeys :设备没有用于文本输入的硬按键;qwerty :设备具有标准硬键盘(无论是否对用户可见);12key :设备具有 12 键硬键盘(无论是否对用户可见)。 |
导航键可用性(Navigation key availability) | navexposed 、navhidden |
navexposed :导航键可供用户使用;navhidden:导航键不可用(例如,位于密封盖子后面)。` |
主要非触摸导航方法(Primary non-touch navigation method) | nonav 、dpad 、trackball 、wheel |
nonav :除了使用触摸屏以外,设备没有其他导航设施;dpad :设备具有用于导航的方向键;trackball :设备具有用于导航的轨迹球;wheel :设备具有用于导航的方向盘(不常见)。 |
平台版本(API 级别)(Platform Version (API level)) | v3 、v4 、v7 等 |
设备支持的 API 级别。例如,v1 对应于 API 级别 1(带有 Android 1.0 或更高版本系统的设备),v4 对应于 API 级别 4(带有 Android 1.6 或更高版本系统的设备)。 |
!请注意:并不是所有的限定符都是在API 1 中加入的,所以,为了防止某些高版本的限定符不被加载(设备版本较低),请务必为所有资源设置默认的资源文件夹。
drawable-en-rUS-land
,这表示当设备处于横屏状态且系统语言为英文时加载该文件夹下的文件。多个限定符必须按照上表的顺序排列,比如:
drawable-hdpi-port/
,错误;
drawable-port-hdpi/
,正确。
每一种资源文件夹不可被嵌套,比如:res/drawable/drawable-en/
。
文件夹的名称是大小写不敏感的(case-insensitive)。在处理之前,资源编译器会将目录名称转换为小写,以避免不区分大小写的文件系统出现问题。 名称中使用的任何大写字母只是为了便于认读。
对于每种限定符类型,仅支持一个值。例如,若要对西班牙语和法语使用相同的 Drawable 文件,则您肯定不能拥有名为 drawable-rES-rFR/
的目录,而是需要两个包含相应文件的资源目录,如 drawable-rES/
和 drawable-rFR/
。然而,实际上您无需将相同的文件都复制到这两个位置。相反,您可以创建指向资源的别名。
假设您有一个应用图标 icon.png
,并且需要不同区域设置的独特版本。 但是,加拿大英语和加拿大法语这两种区域设置需要使用同一版本。 您可能会认为需要将相同的图像复制到加拿大英语和加拿大法语对应的资源目录中,但事实并非如此。 相反,您可以将用于二者的图像另存为 icon_ca.png
(除 icon.png
以外的任何名称),并将其放入默认 res/drawable/
目录中。然后,在 res/drawable-en-rCA/
和 res/drawable-fr-rCA/
中创建 icon.xml
文件,使用 <bitmap>
标签; 元素引用 icon_ca.png
资源。这样,您只需存储 PNG 文件的一个版本和两个指向该版本的小型 XML 文件。(XML 文件示例如下。)
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/icon_ca" />
如果将此文件另存为 icon.xml
(例如,在备用资源目录中,另存为 res/drawable-en-rCA/
),则会编译到可作为 R.drawable.icon
引用的资源中,但实际上它是 R.drawable.icon_ca
资源(保存在 res/drawable/
中)的别名。
要创建指向现有布局的别名,请使用包装在 <merge>
标签中的 <include>
元素。例如:
<?xml version="1.0" encoding="utf-8"?>
<merge>
<include layout="@layout/main_ltr"/>
</merge>
如果将此文件另存为 main.xml
,则会编译到可作为 R.layout.main
引用的资源中,但实际上它是 R.layout.main_ltr
资源的别名.
要创建指向现有字符串的别名,只需将所需字符串的资源 ID 用作新字符串的值即可。例如:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello</string>
<string name="hi">@string/hello</string>
</resources>
R.string.hi
资源现在是 R.string.hello
的别名。
其他简单数值资源的别名使用与Strings类似,例如:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="red">#f00</color>
<color name="highlight">@color/red</color>
</resources>
请务必提供默认资源。比如,如果应用支持多种语言,请始终包含不带语言和区域限定符的 values/
目录(用于保存字符串)。相反,如果您将所有字符串放入带有语言和区域限定符的目录中,则在语言设置不支持您的字符串的设备上运行应用时,应用将会崩溃。
同样,如果您根据屏幕方向提供不同的布局资源,则应选择一个方向作为默认方向。 例如,不要在 layout-land/
和 layout-port/
中分别提供横向和纵向的布局资源,而是保留其中之一作为默认设置,例如:layout/
用于横向,layout-port/
用于纵向。
当您请求要为其提供备用资源的资源时,Android 会根据当前的设备配置选择要在运行时使用的备用资源。假设Drawable 目录分别包含相同图像的不同版本:
drawable/
drawable-en/
drawable-fr-rCA/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/
假设某个设备的配置参数如下:
Locale = en-GB
Screen orientation = port
Screen pixel density = hdpi
Touchscreen type = notouch
Primary text input method = 12key
设备最终加载的是drawable-en-port
目录下的资源。
系统使用以下逻辑决定要使用的资源:
1、 淘汰与设备配置冲突的资源文件:
drawable-fr-rCA/
目录与 en-GB
区域设置冲突,因而被淘汰。
drawable/
drawable-en/
drawable-fr-rCA/ //被淘汰
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/
2、 选择上表中(下一个)优先级最高的限定符。(先从 MCC 开始,然后下移。)
3、 是否有资源目录包括此限定符?
若无,请返回到第 2 步,看看下一个限定符。(在该示例中,除非达到语言限定符,否则答案始终为“否”。)
若有,请继续执行第 4 步。
4、淘汰不含此限定符的资源目录。在该示例中,系统会淘汰所有不含语言限定符的目录:
drawable/ //淘汰
drawable-en/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/ //淘汰
drawable-port-notouch-12key/ //淘汰
5、返回并重复第 2 步、第 3 步和第 4 步,直到只剩下一个目录为止。在此示例中,屏幕方向是下一个判断是否匹配的限定符。因此,未指定屏幕方向的资源被淘汰:
drawable-en/ //淘汰
drawable-en-port/
drawable-en-notouch-12key/ //淘汰
!请注意:注:限定符的优先顺序(上表 中)比与设备完全匹配的限定符数量更加重要。例如,在上面的第 4 步中,列表剩下的最后选项包括三个与设备完全匹配的限定符(方向、触摸屏类型和输入法),而 drawable-en
只有一个匹配参数(语言)。但是,语言的优先顺序高于其他两个限定符,因此 drawable-port-notouch-12key
被淘汰。
您在应用中提供资源后,可通过引用其资源 ID 来获取该资源,所有的资源ID均被定义在R类 中。
资源 ID 由以下部分组成:
string
、drawable
和 layout
。访问资源的方法有两种:
在代码中:使用来自 R 类的某个子类的静态整型数,例如:
R.string.hello
string 是资源类型,hello 是资源名称。
在 XML 中:使用同样与您 R 类中定义的资源 ID 对应的特殊 XML 语法,如:
@string/hello
string 是资源类型,hello 是资源名称。
ImageView imageView = (ImageView) findViewById(R.id.myimageview);
imageView.setImageResource(R.drawable.myimage);
// Load a background for the current screen from a drawable resource getWindow().setBackgroundDrawableResource(R.drawable.my_background_image) ;
// Set the Activity title by getting a string from the Resources object, because // this method requires a CharSequence rather than a resource ID getWindow().setTitle(getResources().getText(R.string.main_title));
// Load a custom layout for the current screen setContentView(R.layout.main_screen);
// Set a slide in animation by getting an Animation from the Resources object mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.hyperspace_in));
// Set the text on a TextView object using a resource ID TextView msgTextView = (TextView) findViewById(R.id.msg);
msgTextView.setText(R.string.hello_message);
<Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/submit" />
如果您具有以下资源文件,其中包括一个颜色资源和一个字符串资源:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="opaque_red">#f00</color>
<string name="hello">Hello!</string>
</resources>
您可以在以下布局文件中使用这些资源来设置文本颜色和文本字符串:
<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:textColor="@color/opaque_red" android:text="@string/hello" />
要引用系统资源,您需要加入包名称。 例如:
<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:textColor="@android:color/secondary_text_dark" android:text="@string/hello" />
要引用样式属性,名称语法几乎与普通资源格式完全相同,只不过将 at 符号 (@) 改为问号 (?),资源类型部分为可选项。 例如:
?[<package_name>:][<resource_type>/]<resource_name>
例如,您可以通过以下代码引用一个属性,将文本颜色设置为与系统风格主题的“主要”文本颜色匹配:
<EditText id="text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:text="@string/hello_world" />
在以上代码中,android:textColor
属性表示当前风格主题中某个样式属性的名称。
Android 包含许多标准资源,例如样式、风格主题和布局。要访问这些资源,请通过 android 包名称限定您的资源引用。例如,您可以将 Android 提供的布局资源用于 ListAdapter
中的列表项:
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myarray));
simple_list_item_1
是平台为 ListView
中的项目定义的布局资源。您可以使用它,而不必自行创建列表项布局。
有些设备配置可能会在运行时发生变化(例如屏幕方向、键盘可用性及语言)。 发生这种变化时,Android 会重启正在运行的 Activity(先后调用 onDestroy() 和 onCreate())。重启行为旨在通过利用与新设备配置匹配的备用资源自动重新加载您的应用,来帮助它适应新配置。
要妥善处理重启行为,Activity 必须通过常规的Activity 生命周期恢复其以前的状态,在 Activity 生命周期中,Android 会在销毁 Activity 之前调用 onSaveInstanceState(),以便您保存有关应用状态的数据。 然后,您可以在 onCreate() 或 onRestoreInstanceState() 期间恢复 Activity 状态。
但是,重启应用并恢复大量数据不仅成本高昂,而且给用户留下糟糕的使用体验。 在这种情况下,您有两个其他选择:
在配置变更期间保留对象:
自行处理配置变更:
如果重启 Activity 需要恢复大量数据、重新建立网络连接或执行其他密集操作,那么因配置变更而引起的完全重启可能会给用户留下应用运行缓慢的体验。 此外,依靠系统通过 onSaveInstanceState() 回调为您保存的 Bundle,可能无法完全恢复 Activity 状态,因为它 并非设计用于携带大型对象(例如位图),而且其中的数据必须先序列化,再进行反序列化, 这可能会消耗大量内存并使得配置变更速度缓慢。
在这种情况下,如果 Activity 因配置变更而重启,则可通过保留 Fragment 来减轻重新初始化 Activity 的负担。此Fragment可能包含对您要保留的有状态对象的引用。
当 Android 系统因配置变更而关闭 Activity 时,不会销毁您已标记为要保留的 Activity 的Fragment。您可以将此类Fragment添加到 Activity 以保留有状态的对象。
要在运行时配置变更期间将有状态的对象保留在Fragment中,请执行以下操作:
1、继承 Fragment 类并声明对有状态对象的引用。
2、在创建Fragment后调用 setRetainInstance(boolean)
。
3、将Fragment添加到 Activity。
4、重启 Activity 后,使用 FragmentManager 检索Fragment。
public class RetainedFragment extends Fragment {
// data object we want to retain
private MyDataObject data;
// this method is only called once for this fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
!请注意:尽管您可以存储任何对象,但是切勿传递与 Activity 绑定的对象,例如,Drawable、Adapter、View 或其他任何与 Context 关联的对象。否则,它将泄漏原始 Activity 实例的所有视图和资源。 (泄漏资源意味着应用将继续持有这些资源,但是无法对其进行垃圾回收,因此可能会丢失大量内存。)
然后,使用 FragmentManager 将Fragment添加到 Activity。在运行时配置变更期间再次启动 Activity 时,您可以获得Fragment中的数据对象。 例如,按如下所示定义 Activity:
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
// the data is available in dataFragment.getData()
...
}
@Override
public void onDestroy() {
super.onDestroy();
// store the data in the fragment
dataFragment.setData(collectMyLoadedData());
}
}
如果应用在特定配置变更期间无需更新资源,并且因性能限制您需要尽量避免重启,则可声明 Activity 将自行处理配置变更,这样可以阻止系统重启 Activity。
!请注意:自行处理配置变更可能导致备用资源的使用更为困难,因为系统不会为您自动应用这些资源。 只能在您必须避免Activity因配置变更而重启这一万般无奈的情况下,才考虑采用自行处理配置变更这种方法,而且对于大多数应用并不建议使用此方法。
要声明由 Activity
处理配置变更,请在清单文件中编辑相应的 <activity>
标签,以包含 android:configChanges
属性以及代表要处理的配置的值。android:configChanges
属性的文档中列出了该属性的可能值(最常用的值包括 “orientation
” 和 “keyboardHidden
“,分别用于避免因屏幕方向和可用键盘改变而导致重启)。您可以在该属性中声明多个配置值,方法是用 ” | ” 字符分隔这些配置值:
<activity android:name=".MyActivity" android:configChanges="orientation|keyboardHidden" android:label="@string/app_name">
当orientation 或 keyboardHidden
配置发生变化时,MyActivity 不会重启。相反,MyActivity
会收到对 onConfigurationChanged()
的调用。向此方法传递 Configuration
对象指定新设备配置。您可以通过读取 Configuration
中的字段,确定新配置,然后通过更新界面中使用的资源进行适当的更改。调用此方法时,Activity
的 Resources
对象会相应地进行更新,以根据新配置返回资源,这样,您就能够在系统不重启 Activity
的情况下轻松重置 UI 的元素。
!请注意:从 Android 3.2(API 级别 13)开始,当设备在纵向和横向之间切换时,“屏幕尺寸”也会发生变化。因此,在开发针对 API 级别 13 或更高版本系统的应用时,若要避免由于设备方向改变而导致运行时重启,则除了 “orientation
” 值以外,您还必须添加 “screenSize
” 值。即,您必须声明 android:configChanges="orientation|screenSize"
。
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}