第3章
Activity和界面布局
Activity是Android应用程序最主要的展示窗口。本章首先介绍Android应用的组成
和有关Activity的基础知识;其次介绍基于XML文件完成Activity布局的方法、在Activit
中通过Java编程方式设定布局的方法,以及Android的资源管理与使用方法;最后介绍常用
y 
的布局方式,内容涉及线性布局、相对布局、表格布局、网格布局、帧布局、约束布局。

3.1 
Activity及其生命周期
3.1.1 
Android 
应用的基本组件
一般来说,Android应用程序由Activity、ContentProvider、Service、BroadcastReceiver等
组成。当然,有些应用程序可能只包含其中部分而非全部。它们在Andinfs.l清
单文件中以不同的XML标签声明后,才可以在应用程序中使用。
rodMaietxm

1.Activity 

Activity一般含有一组用于构建用户界面(UI)的Widget控件,如按钮Buton、文本
框EditText、列表ListView等,实现与用户的交互,相当于Windows应用程序的窗口或
网络应用程序的Web页面。一个功能完善的Android应用程序一般由多个Activity构
成,这些Activity之间可互相跳转,可进行页面间的数据传递。例如,显示一个E-mail通
讯簿列表的界面就是一个Activity,而编辑通讯簿界面则是另一个Activity。

2.ContentProvider 

ContentProvider是Android系统提供的一种标准的数据共享机制。在Android平
台下,一个应用程序使用的数据存储都是私有的,其他应用程序是不能访问和使用的。私
有数据可以是存储在文件系统中的文件,也可以是SQLite中的数据库。当需要共享数据
时,ContentProvider提供了应用程序之间数据交换的机制。一个应用程序通过实现一个
ContentProvider的抽象接口将自己的数据暴露出去,并且隐蔽了具体的数据存储实现, 
这样既实现了应用程序内部数据的保密性,又能够让其他应用程序使用这些私有数据,同
时实现了权限控制,保护了数据交互的安全性。


第3章 Activity和界面布局 61 
3.Service 
Service是相对于Activity独立且可以保持后台运行的服务,相当于一个在后台运行的
没有界面的Activity。如果应用程序并不需要显示交互界面但却需要长时间运行,就需要使
用Service。例如,在后台运行的音乐播放器,为了避免音乐播放器在后台运行时被终止而停
播,需要为其添加Service,通过调用Context.startService()方法,让音乐播放器一直在后台运
行,直到使用者再调出音乐播放器界面并关掉它为止。用户可以通过StartService()方法启
动一个Service,也可以通过bindService()方法来绑定一个Service并启动它。
4.BroadcastReceiver 
在Android系统中,广播是一种广泛运用的在应用程序之间传输信息的机制。而
BroadcastReceiver是用来接收并响应广播消息的组件,不包含任何用户界面。它可以通
过启动Activity或者Notification通知用户接收重要信息。Notification能够通过多种方
法提示用户,包括闪动背景灯、振动设备、发出声音或在状态栏上放置一个持久的图标。
Activity、Service和BroadcastReceiver都是由Intent异步消息激活的。Intent用于
连接以上各个组件,并在其间传递消息。例如,广播机制一般通过下述过程实现:首先在
需要发送信息的地方,把要发送的信息和用于过滤的信息(如Action、Category)装入一个
Intent对象,然后通过调用Context.sendBroadcast()或sendOrderBroadcast()方法,把
Intent对象以广播方式发送出去。Android系统会对所有已经注册的BroadcastReceiver 
检查其Intent过滤器(IntentFilter)是否与发送的Intent相匹配,若匹配就会调用其
onReceive()方法,接收广播并响应。例如,对于一个电话程序,当有来电时,电话程序就
自动使用BroacastReceiver取得对方的来电消息并显示。使用Intent还可以方便地实现
各个Activity间的跳转和数据传递。
3.1.2 什么是Activity 
Activity是Android四大组件中最基本的组件,是Android应用程序中最常用也是
最重要的部分。在应用程序中,用户界面主要通过Activity呈现,包括显示控件、监听和
处理用户的界面事件并做出响应。Activity在界面上的表现形式有全屏窗体、非全屏悬
浮窗体、对话框等。在模拟器上运行应用程序时,可以按HOME 键或回退键退出当前
Activity。
对于大多数与用户交互的程序来说,Activity是必不可少的,也是非常重要的。刚开
始接触Android应用程序时,可以暂且将Activity简单地理解为用户界面。新建一个
Android项目时,系统默认生成一个启动的主Activity,其默认的类名为MainActivity,源
码文件中的主要内容如代码段3-1所示。 
代码段3-1 MainActivity 源代码
package edu.hebust.zxm.myfirstapplication; 
import androidx.appcompat.app.AppCompatActivity; 
//AppCompatActivit 是android.app.Activity 的子类

62 Android软件开发教程(第3版·微课版) 
import android.os.Bundle; //用于映射字符串值
public class MainActivity extends AppCompatActivity { 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
//设置布局,它加载了res/layout/activity_main.xml 中定义的界面元素 
} 
}
应用程序中的每个Activity都必须继承自android.app.Activity类并重写(Override) 
其OnCreate()方法。
Activity通常要与布局资源文件(res/layout目录下的XML 文件)相关联,并通过
setContentView()方法将布局呈现出来。在Activity类中通常包含布局控件的显示、界
面交互设计、事件的响应设计以及数据处理设计、导航设计等内容。
一个Android应用程序可以包含一个或多个Activity,一般在程序启动后会首先呈
现一个主Activity,用于提示用户程序已经正常启动并显示一个初始的用户界面。需要
注意的是,应用程序中的所有Activity都必须在AndroidManifest.xml文件中添加相应
的声明,并根据需要设置其属性和<intent-filter>。例如,代码段3-2 含有对两个
Activity(MainActivity和SecondActivity)的声明,代码中有两个<activity>元素,第一
个为系统默认生成的MainActivity,第二个是新建的SecondActivity,其中的
MainActivity是程序入口。 
代码段3-2 AndroidManifest.xml 文件中的声明
<application 
android:allowBackup="true" 
android:icon="@drawable/ic_launcher" 
android:label="@string/app_name" 
android:theme="@style/AppTheme" > 
<activity 
android:name="edu.hebust.zxm.myfirstapplication.MainActivity" 
android:exported="true" > 
<intent-filter> 
<action android:name="android.intent.action.MAIN" /> 
<category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter> 
</activity> 
<activity 
android:name="edu.hebust.zxm.myfirstapplication.SecondActivity" 
android:label="SecondActivity" > 
</activity> 
</application>

第3章Activity和界面布局63
3.1.3 
Activity 
的生命周期
所有Android组件都具有自己的生命周期,生命周期是指从组件建立到组件销毁的
整个过程。在生命周期中,组件会在可见、不可见、活动、非活动等状态中不断变化。

Activity的生命周期指Activity从启动到销毁的过程。生命周期由系统控制,程序
无法改变,但可以用onSaveInstanceState()方法保存其状态。了解Activity的生命周期
有助于理解Activity的运行方式和编写正确的Activity代码。

Activity在生命周期中表现为4种状态,分别是活动状态、暂停状态、停止状态和非
活动状态。处于活动状态时,Activity在用户界面中处于最上层,能完全被用户看到,并
与用户进行交互。处于暂停状态时,Activity在界面上被部分遮挡,该Activity不再位于
用户界面的最上层,且不能与用户进行交互。处于停止状态时,Activity在界面上完全不
能被用户看到,也就是说这个Activity被其他Activity全部遮挡。非活动状态指不在以
上3种状态中的Activity。

参考AndroidSDK官网文档中的说明,Activity生命周期如图3-1所示。该示意图中涉
及的方法被称为生命周期方法,当Activity状态发生改变时,相应的方法会被自动调用。

anriaAciiy类是Andod提供的基类, tvt

dod.pp.tvtri应用程序中的每个Aciiy都继承
自该类,通过重写父类的生命周期方法来实现自己的功能。在代码段3-1中,@Overide 
表示重写父类的onCreate()方法,Bundle类型的参数保存了应用程序上次关闭时的状
态,并且可以通过一个Activity传递给下一个Activity。在Activity的生命周期中,只要
离开了可见阶段(即失去了焦点),它就很可能被进程终止,这时就需要一种机制能保存当
时的状态,这就是其参数savedInstanceState的作用。

(1)启动Activity时,系统会先调用其onCreate()方法,然后调用onStart()方法,最
后调用onResume()方法,Activity进入活动状态。
(2)当Activity被其他Activity部分遮盖或被锁屏时,Activity不能与用户交互,会
调用onPause()方法,进入暂停状态。
(3)当Activity由被遮盖回到前台或解除锁屏时,会调用onResume()方法,再次进
入活动状态。
(4)当切换到新的Activity界面或按Home键回到主屏幕时,当前Activity完全不
可见,转到后台。此时会先调用onPause()方法,然后调用onStop()方法,Activity进入
停止状态。
(5)当Activity处于停止状态时,用户后退回到此Activity,会先调用onRestart()方
法,然后调用onStart()方法,最后调用onResume()方法,再次进入运行状态。
(6)当Activity处于被遮盖状态或者后台不可见,即处于暂停状态或停止状态时,如
果系统内存不足,就有可能杀死这个Activity。而后用户如果返回Activity,则会再依次
调用onCreate()方法、onStart()方法、onResume()方法,使其进入活动状态。
(7)用户退出当前Activity时,先调用onPause()方法,然后调用onStop()方法,最
后调用onDestroy()方法,结束当前Activity。
Activity生命周期可分为可视生命周期和活动生命周期。可视生命周期是Activity 


64Android软件开发教程(第3版·微课版) 
图3-
1 
Activity生命周期

在界面上从可见到不可见的过程,开始于onStart(), 结束于onStop()。活动生命周期是
Activity在屏幕的最上层,并能够与用户交互的阶段,开始于onResume(), 结束于
onPause()。在Activity的状态变换过程中,onResume() 和onPause() 经常被调用,因此
这两个方法中应使用简单、高效的代码。

编程人员可以通过重写生命周期方法在Activity中定义当处于什么状态时做什么事
情。例如,当第一次启动一个Activity时,会调用onCreate() 方法,则初始化的操作可以
写在这个方法中。


第3章 Activity和界面布局 65 
【例3-1】 示例工程Demo_03_ActivityLifeCycle用于验证Activity生命周期方法被
调用的情况,其主要代码如代码段3-3所示。 
代码段3-3 验证Activity 生命周期方法的示例程序
//package 和import 语句省略
public class MainActivity extends AppCompatActivity { 
private static final String TAG = "生命周期示例"; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
Log.d(TAG, "-- onCreate()被调用--"); 
} 
@Override 
protected void onStart() { 
super.onStart(); 
Log.d(TAG, "-- onStart()被调用--"); 
} 
. //其余代码类似
}
运行这个Activity后,在Logcat面板中能看到给出的提示信息,从中可看到Activity 
的生命周期是如何运行的。例如,启动这个Activity后Logcat面板输出的提示信息如
图3-2所示,onCreate()、onStart()和onResume()方法被依次调用;关闭这个Activity 
时,Logcat面板输出的提示信息如图3-3所示,onPause()、onStop()和onDestroy()方法
被依次调用。
图3-2 Activity启动时调用的生命周期方法
图3-3 Activity结束时调用的生命周期方法
Activity的生
命周期

66Android软件开发教程(第3版·微课版) 
3.1.4 
Activity 
的启动模式
主Activity在启动应用程序时就创建完毕,在其中可以显示XML 布局信息、指定处
理逻辑等。对于功能较复杂的应用程序,往往一个界面是不够用的,这就需要多个
Activity来实现不同的用户界面。在Android系统中,所有的Activity由堆栈进行管理, 
Activity栈遵循“后进先出”的规则。如图3-4所示,当一个新的Activity被执行后,它将
会被放置到堆栈的最顶端,并且变成当前活动的Activity,而先前的Activity原则上还是
会存在于堆栈中,但它此时不会在前台。Android系统会自动记录从首个Activity到其
他Activity的所有跳转记录并且自动将以前的Activity压入系统堆栈,用户可以通过编
程的方式删除历史堆栈中的Activity实例。


图3-
4 
Activity栈示意图

Activity启动模式有4种,分别是standard、singleTop、singleTask、singleInstance。
可根据实际需求为Activity设置对应的启动模式,从而避免创建大量重复的Activity等
问题。设置Actiiy启动模式的方法是在Andrinfs.l里对应的<aciiy>标

vtodMaietxmtvtndroilaunchMod

签中设置ad:e属性,如图35所示。


图3在AXML 
中设置Ay的启动模式

-
5 
ndroidManifest.ctivit

(1)standard是默认模式,如果Activity已经启动,再次启动会创建一个新的


第3章 Activity和界面布局 67 
Activity实例叠在前一个Activity之上。此时Activity是在同一个任务栈里,只不过是
不同的实例。如果点击手机上的回退键会按照栈顺序依次退出。
(2)singleTop模式是可以有多个实例的,但是不允许多个相同的Activity叠加在一
起,如果Activity在栈顶时启动相同的Activity,则不会创建新的实例。
(3)singleTask 模式中每个Activity只有一个实例。在同一个应用程序中启动
Activity时,若它不存在,则会在当前创建一个新的实例;若存在,则会把任务列表中在其
之上的其他Activity取消并调用它的onNewIntent()方法。
(4)singleInstance模式只有一个实例,不允许有别的Activity存在,也就是说,一个
实例栈中只有一个Activity。
3.1.5 Context 及其在Activity 中的应用
Context的中文解释是“上下文”或“环境”,在Android中应该理解为“场景”。例如, 
正在打电话时,场景就是用户所能看到的在手机里显示出来的拨号键盘,以及虽然看不
到,但是却在系统后台运行的对应着拨号功能的处理程序。
Context描述的是一个应用程序环境的上下文信息,是访问全局信息(如字符串资
源、图片资源等)的接口。通过它可以获取应用程序的资源和类,也包括一些应用级别操
作,如启动Activity、启动和停止Service、发送广播、接收Intent信息等。也就是说,如果
需要访问全局信息,就要使用Context。在代码段3-4中,this指的是这个语句所在的
Activity对象,同时也是这个Activity的Context。 
代码段3-4 通过Context 获取Activity 上下文中的字符串信息
public class MainActivity extends AppCompatActivity { 
private TextView tv; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
tv = new TextView(this); //通过this 得到当前Activity 的上下文信息 
tv.setText(R.string.hello_world); //通过Context 得到字符串资源 
setContentView(tv); 
} 
}
Android系统中有很多Context对象。例如,前述的Activity继承自Context,也就
是说每个Activity对应一个Context;Service也继承自Context,每个Service也对应一个
Context。
常用的Context对象有两种:一种是Activity的Context;另一种是Application的
Context。二者的生命周期不同:Activity的Context生命周期仅在Activity存在时,也
就是说,如果Activity 已经被系统回收了,那么对应的Context也就不存在了;而
Application的Context生命周期却很长,只要应用程序运行着,这个Context就是存在
的,所以要根据自己程序的需要使用合适的Context。

68Android软件开发教程(第3版·微课版) 
3.布局及其加载
2 

Activity主要用于呈现用户界面,包括显示UI控件、监听并处理用户界面事件并做
出响应等。从本节开始,将系统地介绍Android的界面布局及其加载与控制。

3.2.1 
View 
类和ViewGroup 
类
在一个Android应用程序中,用户界面一般由一组View和ViewGroup对象组成。

View对象是继承自View基类的可视化控件对象,是Android平台上表示用户界面
的基本单元,如TextView、Buton、CheckBox等。View是所有可视化控件的基类,提供
了控件绘制和事件处理的属性和基本方法,任何继承自View的子类都会拥有View类的
属性及方法。表3-1给出了View类的部分常用属性的说明。View及其子类的相关属性
既可以在XML布局文件中进行设置,也可以通过成员方法在Java代码中动态设置。

表3-
1 
View类的部分常用属性

XML属性在Java代码中对应的方法功能及使用说明
android:background setBackgroundResource(int) 设置背景颜色
android:clickable setClickable(boolean) 设置是否响应点击事件
android:focusable setFocusable(boolean) 设置View控件是否能捕获焦点
android:id setId(int) 设置View控件标识符
android:layout_width setWidth(int) 设置宽度
android:layout_height setHeight(int) 设置高度
android:text setText(CharSequence)/setText(int) 设置控件上显示的文字
android:textSize setTextSize(float) 设置控件上显示文字的大小
android:textColor setTextColor(int) 设置控件上显示文字的颜色
android:visibility setVisibility(int) 设置View控件是否可见

ViewGroup类是View类的子类,与View类不同的是,它可以充当其他控件的容
器。ViewGroup类作为一个基类为布局提供服务,其主要功能是装载和管理一组View 
和其他ViewGroup,可以嵌套ViewGroup和View对象。Android用户界面中的控件都
是按照层次树的结构堆叠的,其关系如图3-6所示,而它们共同组建的顶层视图可以由应
用程序中的Activity调用setContentView()方法来显示。Android中的一些复杂控件
(如Galey、GridView等)都继承自ViewGroup。

一般很少直接用View和ViewGroup来设计界面布局,更多的时候是使用它们的子
类控件或容器来构建布局。常见用布局和UI控件的继承结构如图3-7所示。每个View 
和ViewGroup对象都支持它们自己的各种属性。一些属性对所有View对象可用,因为
它们是从View基类继承而来的,如id属性;而有些属性只有特定的某一种View对象和
它们的子类可用,如TextView及其子类支持textSize属性。


第3章Activity和界面布局69
图3-
6 
View 
与ViewGroup的关系


图3-
7 
常用布局和UI 
控件的继承结构

3.2.2 
XML 
布局及其加载
在Android应用程序中,常见的布局方式有线性布局(LinearLayout)、相对布局
(RelativeLayout)、表格布局(TableLayout)、网格布局(GridLayout)、帧布局(FrameLayout)、
约束布局(ConstraintLayout)等。这些布局都通过ViewGroup的子类实现。

界面的布局可以在XML 文件中进行设置,也可以通过Java代码设计实现。如果采
用第一种方式,则需要在资源文件夹res\layout中定义相应的布局文件。这个XML 布
局文件由许多View对象嵌套组成。如果布局中有多个元素,那么最顶层的根节点必须
是ViewGroup对象;如果整个布局只有一个元素,那么最顶层元素就是唯一的元素,它可
以是一个单一的UI 对象。

代码段3-lyotxm在其中声明了布局的实例,

5是一个自定义的布局文件myau.l, 该例
采用线性布局,布局中包括一个TextView控件。


70 Android软件开发教程(第3版·微课版) 
代码段3-5 自定义的XML 布局文件
<? xml version="1.0" encoding="utf-8"? > 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" 
android:layout_width="match_parent" 
android:layout_height="match_parent" > 
<TextView 
android:id="@+id/tvHello" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:text="@string/hello" 
/> 
</LinearLayout> 
定义了布局文件之后,需要在Activity 中的onCreate()回调方法中通过调用
setContentView()方法来加载这个布局,如代码段3-7所示。 
代码段3-6 通过重写onCreate()方法加载用户界面的布局
public class MainActivity extends Activity { 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.mylayout); //加载布局 
} 
} 
3.2.3 在Activity 中定义和加载布局
除了上述直接调用已经设定好的XML布局外,还可以在Java代码中直接定义并加
载某种布局,此时就不需要在工程的res文件夹下存放XML布局文件了。在将UI对象
实例化并设置属性值后,通过调用addView()方法可将其添加到设定的布局。
【例3-2】 示例工程Demo_03_DefineLayoutInActivity演示在Java代码中定义并引
用布局的方法。
此例是通过在MainActivity中添加线性布局而非通过XML 布局文件来设置布局
的。通过循环语句定义了3个按钮,并通过addView()方法将其添加到布局中,如代码
段3-7所示。 
代码段3-7 在Activity 中设定布局
public class MainActivity extends AppCompatActivity { 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
LinearLayout myLayout=new LinearLayout(this); 
//通过上下文设定线性布局对象

第3章 Activity和界面布局 71 
myLayout.setGravity(Gravity.CENTER_HORIZONTAL); 
myLayout.setOrientation(LinearLayout.VERTICAL); // 垂直布局 
myLayout.setPadding(0,20,0,0); //设置左、上、右、下边距 
setContentView(myLayout); //加载布局 
Button myBtn; //定义按钮对象 
for (int i=1; i<4; i++){ //添加几个按钮 
myBtn=new Button(this); 
myBtn.setText("按钮" + i); 
myBtn.setTextSize(20); //设置字体大小 
myBtn.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); 
//设置按钮高度 
myLayout.addView(myBtn); //添加到布局中 
myBtn.getLayoutParams().width=500; //设置按钮宽度 
} 
} 
}
示例工程的运行结果如图3-8所示。
图3-8 示例工程的运行结果
3.2.4 资源的管理与使用
在Android系统中,对字符、颜色、图像、音频、视频等资源的使用与管理也是很方便的, 
只要引用或设置资源文件夹res下的相关媒体文件或XML文件,就可以实现相关功能。
Android应用程序中,XML布局和资源文件并不包含在Activity的Java源码中,各
种资源文件由系统自动生成的R文件来管理。每个资源类型在R 文件中都有一个对应
的内部类。例如,类型为layout的资源项在R 文件中对应的内部类是layout,而类型为
string的资源项在R文件中对应的内部类就是string。R文件的作用相当于一个项目字
典,项目中的用户界面、字符串、图片、声音等资源都会在对应的内部类中创建其唯一的
id,当项目中使用这些资源时,会通过该id得到资源的引用。如果程序开发人员变更了
任何资源文件的内容或属性,R文件会随之变动并自动更新其相应的内部类,开发者不需
要也不能修改此文件。
在Java程序中通过R文件引用资源的方法是“R.资源类型.资源名称”,其中,资源类
型可以是图像、字符串或布局文件,资源名称是资源文件名或XML文件中的对象名。例

72 Android软件开发教程(第3版·微课版) 
如:R.drawable.background表示引用资源文件夹中的res\drawable\background.png图
片文件;R.string.title表示引用资源文件res\values\string.xml中定义的title字符串;R. 
layout.activity_main表示引用资源文件夹中的res\layout\activity_main.xml布局文件; 
R.id.tv_result表示引用布局文件中id为tv_result的TextView对象。
1.图片资源的管理与使用
AndroidStudio工程项目提供了mipmap文件夹和drawable文件夹管理图片资源文
件。新建工程项目时,系统会在资源文件夹res中自动创建多个drawable或mipmap文
件夹,如drawable-hdpi、drawable-mdpi、mipmap-hdpi、mipmap-mdpi等,具体取决于
AndroidStudio的版本。当应用程序安装在不同显示分辨率的终端上时,程序会自适应
地选择加载某个文件夹中的资源。例如,一部屏幕密度为320 的手机,会自动使用
drawable_xhdpi文件夹下的图片。如果有默认文件夹drawable,则系统在其他dpi文件
夹下找不到图片时会使用drawable中的图片。
谷歌公司建议将应用程序的图标文件放在mipmap文件夹中,这样可以提高系统渲
染图片的速度,提高图片质量,减小GPU 压力。mipmap支持多尺度缩放,系统会根据当
前缩放范围选择mipmap文件夹中适当的图片,而不是像drawable文件夹根据当前设备
的屏幕密度选择恰当的图片。
【例3-3】 示例工程Demo_03_UseImageResource以设置ImageView的图片属性为
例演示了如何在XML文件中引用图片资源。
首先将图片文件复制到工程中的mipmap文件夹下,图3-9是把background.jpg复
制到工程中的效果。
图3-9 在工程中添加图片
在布局XML文件中,通过“@mipmap/图片文件名”的方式引用mipmap文件夹中
的图片文件,实现代码如代码段3-8所示,运行结果如图3-10所示。 
代码段3-8 在XML 文件中引用图片资源
<? xml version="1.0" encoding="utf-8"? >

第3章 Activity和界面布局 73 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 
<TextView 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="在ImageView 中引用图片资源:" 
android:textColor="#000000" 
android:textSize="25sp" 
android:layout_margin="16dp"/> 
<ImageView 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:src="@mipmap/background" 
android:scaleType="centerCrop"/> 
</LinearLayout> 
图3-10 设置ImageView 的图片属性
如果是在Java代码中,则通过“R.mipmap.图片文件名”的方式引用mipmap文件夹
中的图片文件。例如代码段3-9将mipmap文件夹中background.jpg设置为App的
背景。 
代码段3-9 在Activity 中设定App 的背景
protected void onCreate(Bundle savedInstanceState) {

74 Android软件开发教程(第3版·微课版) 
super.onCreate(savedInstanceState); 
this.getWindow().setBackgroundDrawableResource(R.mipmap.background); 
//用指定图片作为背景 
setContentView(R.layout.activity_main); 
} 
2.字符串资源的管理与使用
字符串资源描述文件strings.xml一般位于工程res文件夹下的values子文件夹中。
如果需要在Activity 代码或布局文件中使用字符串,可以在strings.xml文件中的
<resources>标签下添加相应的<string>元素,定义字符串资源。<string>元素的基
本格式如下: 
<string name="字符串名称"> 字符串的内容</string> 
代码段3-10是一个典型的strings.xml示例,其中定义了两个字符串资源。 
代码段3-10 string.xml 代码示例
<? xml version="1.0" encoding="utf-8"? > 
<resources> 
<string name="app_name">MyFirstApplication</string> 
<string name="hello_world">Hello world!</string> 
</resources> 
上述代码段的第1行定义了XML版本与编码方式;第2行以后在<resources>标
签下定义了两个<string>元素,定义了两个字符串,字符串的名称分别为app_name和
hello_world。如果需要在Java程序代码中使用这些字符串,可以用“R.string.字符串名
称”的方式引用。如果在XML文件中使用这些字符串,则用“@string/字符串名称”的方
式引用。Android解析器会从工程的res/values/strings.xml文件里读取相应名称对应
的字符串值并进行替换。
3.数组资源的管理与使用
与字符串资源类似,数组描述文件arrays.xml位于工程res文件夹下的values子文
件夹中。数组资源也定义在<resources>标签下,其基本语法如下: 
<数据类型-array name="数组名"> 
<item>数组元素值1</item> 
<item>数组元素值2</item> 
. 
</数据类型-array> 
代码段3-11是一个典型的arrays.xml示例,在其中定义了两个字符串数组,数组名

第3章 Activity和界面布局 75 
分别是citys和modes。 
代码段3-11 arrays.xml 代码示例
<? xml version="1.0" encoding="utf-8"? > 
<resources> 
<string-array name="citys"> 
<item>北京</item> 
<item>天津</item> 
<item>上海</item> 
</string-array> 
<integer-array name="modes"> 
<item>1</item> 
<item>2</item> 
<item>3</item> 
</integer-array> 
</resources> 
在XML中引用数组资源的方法是“@array/数组名称”,例如: 
<Spinner 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:entries="@array/citys"/> 
在Java代码中引用数组资源的方法是“getResources().getXxxArray(R.array.数组
名称)”,例如: 
String[] citys=getResources().getStringArray(R.array.citys); 
int[] modes=getResources().getIntArray(R.array.modes); 
4.颜色描述资源的管理与使用
颜色描述文件colors.xml位于工程res文件夹下的values子文件夹中,其典型内容
如代码段3-12所示。 
代码段3-12 colors.xml 代码示例
<? xml version="1.0" encoding="utf-8"? > 
<resources> 
<color name="colorPrimary">#3F51B5</color> 
<color name="colorPrimaryDark">#303F9F</color> 
<color name="colorAccent">#FF4081</color> 
</resources> 
在<resources>标签下添加相应的<color>元素,定义颜色资源,其基本格式如下:

76 Android软件开发教程(第3版·微课版) 
<color name="颜色名称"> 该颜色的值</color> 
颜色值通常为8位的十六进制的颜色值,表达式顺序是#aarrggbb,其中aa表示
alpha值(00为完全透明,FF为完全不透明),aa可省略,此时表示一个完全不透明的颜
色;rr表示红色分量值;gg表示绿色分量值;bb表示蓝色分量值。例如,#7F0400FF表
示半透明的蓝色。任何一种颜色的值范围都是十六进制00~FF(0~255)。
在XML中引用颜色资源的方法是“@color/颜色名称”,例如: 
android:textColor="@color/colorAccent" 
在Java代码中引用颜色资源的方法是“getResources().getColor(R.color.颜色名
称)”,或“ContextCompat.getColor(context,R.color.颜色名称)”,例如: 
TextView hello=(TextView)findViewById(R.id.hello); 
hello.setTextColor(getResources().getColor(R.color.colorPrimary)); 
5.引用assets文件夹中的资源
同res文件夹相似,assets也是存放资源文件的文件夹,但res文件夹中的内容会被
编译器所编译,assets文件夹则不会。也就是说,应用程序运行的时候,res文件夹中的内
容会在启动的时候载入内存,assets文件夹中的内容只有在被用到的时候才会载入内存, 
所以一般将一些不经常用到的大资源文件存放在该文件夹下,如应用程序中用到的音频、
视频、图片、文本等文件。
在程序中可以使用“getResources.getAssets().open("文件名")”的方式得到资源文
件的输入流InputStream 对象。
3.3 常用的布局
3.3.1 线性布局LinearLayout 
线性布局将其包含的子元素按水平或者垂直方向顺序排列。布局方向由属性
android:orientation的值来决定,其值为vertical时子元素垂直排列,为horizontal时子元
素水平排列。同时,可使用android:gravity属性调整其子元素向左、向右或居中对齐,或
使用android:padding 属性来微调各子元素的摆放位置,还可以通过设置子元素的
android:layout_weight属性值控制各个元素在容器中的相对大小。
在XML布局文件中,线性布局的子元素定义在<LinearLayout></LinearLayout>标
签之间。每个线性布局的所有子元素,如果垂直分布则仅占一列,如果水平分布则仅占一
行。线性布局中如果子元素所需位置超过一行或一列,不会自动换行或换列,超出屏幕的
子元素将不会被显示。

第3章 Activity和界面布局 77 
【例3-4】 示例工程Demo_03_LinearLayout演示了线性布局的用法。
在AndroidStudio中新建一个工程,选用空白的Activity模板,系统会自动为该
Activity建立一个位于res/layout/中的布局文件,自动建立的内容采用约束布局。可以
把这个约束布局直接修改为线性布局,如代码段3-13所示。本例中采用垂直布局,在布
局中添加了3个按钮,示例工程运行结果如图3-11所示。
图3-11 线性布局示例工程的运行结果 
代码段3-13 线性布局示例
<? xml version="1.0" encoding="utf-8"? > 
<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:gravity="center_horizontal" 
android:paddingTop="8dp"> 
<Button 
android:text="按钮1" 
android:id="@+id/button1" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" /> 
<Button 
android:text="按钮2" 
android:id="@+id/button2" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" /> 
<Button 
android:text="按钮3" 
android:id="@+id/button3" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" /> 
</LinearLayout> 
在代码段3-13中,为每个按钮对象定义了id属性。在XML布局文件中,可以通过
设置android:id属性来给相应的UI元素指定id,通常是以字符串的形式定义一个id,格

78 Android软件开发教程(第3版·微课版) 
式如下: 
android:id="@+id/id 字符串" 
这里在“@+id/”后面的字符是设定的id,@表示XML解析器应该解析id字符串并
把它作为id资源;+表示这是一个新的资源名字,它被创建后应加入R 资源文件中。通
过这个id,可在XML布局或Activity代码中引用相应的UI元素。引用id时不需要符号
+。例如,代码段3-14演示了在Activity中通过id引用布局中的第一个按钮,并设置其
text属性值。 
代码段3-14 通过findViewById()方法引用布局中的UI 对象
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
Button myButton=(Button)findViewById(R.id.button1); 
//取得Button 控件句柄,存储到myButton 对象中 
myButton.setText("hello"); 
//字符串hello 显示在id 为button1 的按钮上面
}
另外,一般情况下每个View 对象都需要设置宽度和高度(layout_width和layout_ 
height)属性。可以指定宽度和高度的绝对值,如50dp,也可指定为match_parent或者
wrap_content。match_parent使UI元素对象扩展以填充布局单元内尽可能多的空间,如
果设置一个元素的layout_width和layout_height属性值为match_parent,它将被强制性
布满整个父容器。而wrap_content使UI元素对象扩展以显示其全部内容,例如, 
TextView和ImageView对象,设置其layout_width和layout_height属性值为wrap_ 
content,将恰好完整显示其内部的文本或图像,UI元素将会根据其内容自动更改大小并
包裹住文字或图片内容。除此之外,还可以通过设置UI元素对象的对齐方式、边距、边
界等,调整其在界面中的位置。例如,代码段3-13中,通过设置根布局的android:gravity 
属性使3个按钮水平居中。
【例3-5】 示例工程Demo_03_BrowserByLinearLayout采用线性布局,实现了一个
简易浏览器界面。
本例演示了线性布局中子元素在容器中的相对大小比例的控制。本例使用了
android:layout_weight属性,该属性用于定义控件对象所占空间分割父容器的比例。
android:layout_weight属性只有在LinearLayout中才有效,其默认值为0。其含义
是一旦View对象设置了该属性,那么该对象的所占空间等于android:layout_width或
layout_height设置的空间加上剩余空间的占比。即LinearLayout如果显式包含layout_ 
weight属性,则会计算两次对象所占尺寸,第一次将正常计算所有View 对象的宽高,第
二次将结合layout_weight的值分配剩余的空间。例如,假设屏幕宽度为L,两个View 
对象的宽度都为match_parent,其layout_weight的值分别是1和2,则两个View的原有
线性布局
LinearLayout

第3章 Activity和界面布局 79 
宽度都为L,那么剩余宽度为L-(L+L)=-L,第一个View对象占比为1/3,所以总宽
度是L+(-L)×1/3=(2/3)L。
一般推荐当使用layout_weight属性时,将android:layout_width或layout_height 
设为0dp,这样layout_weight值就可以简单理解为空间占比了。
示例工程的布局效果预览如图3-12(a)所示,运行结果如图3-12(b)所示。XML布
局文件的内容如代码段3-15所示。
图3-12 线性布局实现简易浏览器界面 
代码段3-15 采用线性布局实现简易浏览器界面
<? xml version="1.0" encoding="utf-8"? > 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" 
android:padding="8dp"> 
<LinearLayout 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:orientation="horizontal"> 
<EditText 
android:id="@+id/editText"