第一章 Android 基础入门
Android 是基于 Linux 的开源操作系统,最初由 Andy Rubin 开放。
1.1 简介
1.1.1 通信技术
1G 很容易被窃听
2,3,4,5G 技术的本质区别是传输速度不同。
2019 年,5G 商用元年。
1.1.3 体系结构
- 应用程序层应用程序的集合。
- 应用程序框架层提供 API。
- 核心类库系统库和 Android 运行时库(包含了 Dalvik 虚拟机,使得每个 Android 应用程序都能运行在独立的进程中)。
- Linux 内核层底层驱动的集合,如显示驱动,音频驱动,照相机驱动等。
1.1.4 Dalvik 虚拟机
基于寄存器架构。执行特有的 dex
文件实现其功能。
功能:
- 对象生命周期管理
- 堆栈管理
- 线程管理
- 安全异常管理
- 垃圾回收
虚拟机编译文件的过程(P4):

ART 模式
启用后,安装 APP 时预编译,并将代码转换成机器语言存储在本地。
提高执行效率。
1.4 Android 程序结构
四大组件在 src/main/AndroidManifest.xml 里注册,这是整个程序的配置文件。 四大组件:
- Activity 活动
- Service 服务
- BroadCastReceive 广播接收器
- ContentProvider 内容提供商
接下来介绍程序工程的结构:
- app 代码和资源
- libs 第三方 jar 包
- src 代码和资源的主目录
- androidTest 调试代码
- main
- java 程序代码
- res 程序资源
- AndroidManifest.xml 整个程序的配置文件,在其中可以配置程序所需的权限和注册程序用到的四大组件。注意这里是申请网络权限和存储权限的地方,不申请就用不了,而且似乎不会报错。
- build.gradle app 构建脚本,包含编译的 SDK 版本,Tools 版本,支持的最低 SDK 版本,支持的目标 SDK 版本。
- build.gradle 安卓程序的构建脚本
- local.properties 指定程序的 SDK 路径。可以通过 sdk.dir 的值指定,一般不需要修改
- settings.gradle 配置子项目
1.5 资源管理与使用
res 目录中。
1.6 调试
输出信息使用 logcat。 v:verbose 详细 d:debug i:info w:warning e:error a:assert 断言 vdiwea
习题
一、填空题
- Dalvik 中的 Dx 工具会把部分 class 文件转换成(dex)文件。
- 如果希望在 XML 布局文件中调用颜色资源,可以使用(@color)调用。
- Android 程序入口的 Activity 是在(AndroidMainifest.xml)文件中注册的。
- Android 中 查看应用程序日志的工具是(LogCat)。
二、判断题
- Dalvik 是 Google 公司设计的用于 Android 平台的虚拟机。 √
- Android 应用程序的主要语言是 Java。√
- Android 系统采用分层架构,分别是应用程序层、应用程序框架层、核心类库和 Linux 内核。√
- 第三代移动通信技术 (3G) 包括 TD-LTE 和 FDD-LTE 两种制式。× 应是 4G。
- Android 程序中,Log.e() 用于输出警告级别的日志信息。× e-error
- 每个 Dalvik 虚拟机实例都是一个独立的进程空间,并且每个进程之间不可以通信。× 可以通信。
三、选择题
- Dalvik 虚拟机是基于(C)的架构。 A. 栈 B. 堆 C. 寄存器 D. 存储器
- Android 项目中的主题和样式资源,通常放在 (C) 目录。 A. res/drawable B. res/layout C. res/values D. assets
- 下列关于 AndroidManifest.xml 文件的说法中,错误的是 (D)。 A. 它是整个程序的配置文件 B. 可以在该文件中配置程序所需的权限 C. 可以在该文件中注册程序用到的组件 D. 该文件可以设置 UI 布局
- Dalvik 虚拟机属于 Android 系统架构中的(C) A. 应用程序层 B. 应用程序框架层 C. 核心类库层 D. Linux 内核层
- Android 中 短信、联系人管理、浏览器等属于 Android 系统架构中的(A) A. 应用程序层 B. 应用程序框架层 C. 核心类库层 D. Linux 内核层
四、简答题
简述 Android 体系结构的层次和特点
见 1.1.3。书 P3。
第二章 Android 常见界面布局
2.1 View 控件
每个界面必须有且只有一个 ViewGroup 容器。
2.2 界面布局编写方式
2.2.1 XML 布局文件 中编写布局
布局文件放在 res/layout
,用标签定义布局,例如 <RelativeLayout></RelativeLayout>。
2.2.2 Java 代码中编写布局
P32
2.3 布局通用属性(P32)
android:id
// 标识
android:layout_width
// 布局的宽度
android:layout_height
// 布局的高度
android:background
// 布局背景
android:layout_margin
// 边界距离,外距
android:padding
// 内距
2.4 线性布局
<LinearLayout></LinearLayout>
- 排列方式:水平或者竖直排列。 android:orientation=”vertical”
// 控件自上到下
android:orientation=”horizontal”
// 控件从左到右 - 权重 android:layout_weight=”1″
// 设置权重
2.5 相对布局
<RelativeLayout></RelativeLayout>
相对定位指定子控件的位置。
2.6 表格布局
行列方式的布局。
<TableLayout>
<TableRow>
</TableRow>
</TableLayout>
2.7 帧布局
<FrameLayout></FrameLayout>
习题
一、填空题
- Android 的常见布局都直接或者间接的继承自(ViewGroup)类。
- Android 中 的 TableLayout 继承自(LinearLayout)。
- 表格布局 TableLayout 通过(TableRow)布局控制表格的行数。
- (RelativeLayout)布局通过相对定位的方式指定子控件的位置。
- 在 R.java 文件中,android:id 属性会自动生成对应的(int)类型的值。
二、判断题
- ViewGroup 是盛放界面控件的容器。√
- 如果在帧布局 FrameLayout 中放入三个所有属性都相同的按钮,那么能够在屏幕上显示的是第 1 个被添加的按钮。× 第三个,因为会被覆盖。
- Android 中的布局文件通常放在 res/layout 文件夹中。√
- TableLayout 继承自 LinearLayout, 因此它完全支持 LinearLayout 所支持的属性。√
- LinearLayout 布局中的 android:layout_weight 属性用于设置布局内控件所占的权重。√
三、选择题
- 下列属性中,用于设置线性布局方向的是(A)。 A. orientation B. gravity C. layout gravity D. padding
- 下列选项中,不属于 Android 布局的是(C)。 A. FrameLayout B. LinearLayout C. Button D. RelativeLayout
- 帧布局 FrameLayout 是将其中的组件放在自己的(A)。 A. 左上角 B. 右上角 C. 左下角 D. 右下角
- 对于 XML 布局文件,android:layout_width 属性的值不可以是(D)。 A. match_parent B. fill_parent C. wrap_content D. match_content
- 下列关于 RelativeLayout 的描述,正确的是(C)。 A. RelativeLayout 表示绝对布局,可以自定义控件的 x、y 的位置 B. RelativeLayout 表示帧布局,可以实现标签切换的功能 C. RelativeLayout 表示相对布局,其中控件的位置都是相对位置 D. RelativeLayout 表示表格布局,需要配合 TableRow 一起使用
第三章 Android 常见界面控件
3.1 简单控件
- Textview 文本框
- EditText 文本输入框
- Button 按钮
- ImageView 图片
- RadioButton 单选按钮(圆按钮)
- CheckBox 多选按钮(方按钮)
- Toast 类 轻量级信息提醒机制。
3.2 列表控件
ListView 是类似微信主界面和淘宝搜索界面的列表。
这种列表需要配合数据适配器 Adapter,常见的 Adapter 如下
- BaseAdapter
- getCount 获取 Item 个数
- getItem(int position) 获取对应位置的 Item 对象
- getItemId(int position) 获取 id
- getView(int position,View convertView,ViewGroup Parent) 获取视图
- SimpleAdapter
- ArrayAdapter
注意学习一下 Adapter 怎么定义。
习题
一、判断题
- Android 的控件样式,每一个 XML 属性都对应一个 Java 方法。√
- 当指定 RadioButton 按钮的 android:checked 属性为 true 时,表示未选中状态。× 当然是选中了。
- AlertDialog 对话框能够直接通过 new 关键字创建对象。× 要通过 Builder 对象。
- Toast 是 Android 系统提供的轻量级信息提醒机制,用于向用户提示即时消息。√
- ListView 列表中的数据是通过 Adapter 加载的。√
二、选择题
- 在 XML 布局中定义了一个 Button, 决定 Button 按钮上显示文字的属性是(B) A. android:value B. android:text C. android:id D. android:textvalue
- 下列选项中,(C)用于设置 TextView 中文字显示的大小。 A. android:textSize=”18″ B. android:size=”18″ C. android:textSize=”18sp” D. android:size=”18sp”
- 使用 EditText 控件时,当文本内容为空时,如果想做一些提示,那么可以使用的属性是(D)。 A. android:text B. android:background C. android:inputType D. android:hint
- 为了让一个 imageView 显示一张图片,可以通过设置的属性是(A)。 A. android:src B. android:background C. android: img D. android:value
- 下列关于 ListView 的说法中,正确的是(C) A. ListView 的条目不能设置点击事件 B. ListView 不设 置 Adapter 也能显示数据内容 C. 当教据超出能显示范围时,ListView 自动具有可滚动的特性 D. 若 ListView 当前能显示 10 条,一共有 100 条数据,则产生了 100 个 View
- CheckBox 被选择的监听事件通常使用(B)方法。 A. setOnClickListener B. setOnCheckedChangeListener C. setOnMenuItemSelectedListener D. setOnCheckedListener
- 当使用 EditText 控件时,能够使文本框设置为多行显示的属性是(A)。 A. android:lines B. android:layout_height C. android:textcolor D. android:textsize
- 下列关于 AlertDialog 的描述,错误的是(A) A. 使用 new 关键字创建 AlertDialog 的实例 B. 对话框的显示需要调用 show() 方法 C. setPositiveButton() 方法是 用来设置确定按钮的 D. setNegativeButton() 方法是用来设置取消按钮的
第四章 程序活动单元 Activity
4.1 Activity 生命周期
5 种生命周期的状态:
- 启动状态 十分短暂
- 运行状态 可见的、有焦点的。运行状态的 Activity 具有高优先级,即使内存不足,系统也会先销毁栈底的 Activity 来确保当前的 Activity 正常运行。
- 暂停状态 可见,但无焦点不可操作,例如主界面出现一个弹窗,则主界面就是暂停状态。
- 停止状态 完全不可见就是停止状态。
- 销毁状态 会被清理出内存。
生命周期方法:
- onCreate() 创建界面的时候初始化的函数,一开始就会调用,可以重写这个方法来做一些初始化工作,例如给控件写数据等
- onStart() 即将可见时调用
- onResume() 获取焦点时调用
- onPause() 暂停,被遮挡时调用
- onStop() 不可见时调用
- onRestart() 停止状态启动
- onDestory() 销毁时调用
4.2 Activity 创建、配置、启动、关闭
创建
编译器左上角 new 就行。
配置
编写类继承 ( extend ) activity 类
启动
public void startActivity (Intent intent)
关闭
public void finish()
4.3 Intent 意图和 IntentFilter 匹配
显式和隐式 Intent
- 显式 intent Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);那么就用 intent 的属性来确定需要打开的 Activity 了。 - 隐式 intent 主要有三个属性值:
- action 要完成的动作
- data 传递的数据
- category action 属性的额外信息
IntentFilter
隐式 Intent 会使得系统将其和每一个组件的过滤器相匹配,三个属性值都匹配成功,则唤起相应的组件。
匹配规则:
- action 清单文件中设置 一些 action 属性(
<intent-filter></intent-filter>
),只要 action 匹配上了一条就算匹配上。 - data 清单文件中设置 一些 data 属性(
<intent-filter></intent-filter>
),只要 data 匹配上了一条就算匹配上。 - category 清单文件中设置 一些 category 属性(
<intent-filter></intent-filter>
),隐式的 intent 里的 category 必须包含于(小于等于)清单文件里的 category 属性,否则匹配不上。因此 intent 的 category 如果是空则和所有的 IntentFilter 匹配上
4.4 Activity 之间的跳转
4.4.1 数据传递
- 用 Intent 来做数据传递。 putExtra(String name, …);
// 加入一个属性,第一个参数是属性名,第二个是属性值第二个参数的类型是变化的,因为这个函数有很多的重载。但应该都是基本数据类型。不能传递一个对象的引用。另一个 Activity 取出这个属性这样操作。 getIntent().getStringExtra(String name)
// 如果这个属性的值是 int,就把 String 改成 Int。Boolean→Boolean - 用 Bundle 类传递数据 例如 Intent intent = new Intent() ;
Bundle bundle = new Bundle() ;
bundle.putString(“account”, “小米”);
intent.putExtras(bundle);
startActivity(intent);另一个 Activity 取出 Bundle 这样操作。 getIntent() .getExtras() .getString(“account”);
4.4.2 数据回传
三个方法:
- startActivityForResult( Intent intent, int requestCode); 第一个参数是意图对象,第二个是请求码,标识请求来源。这个函数用来开启一个 Activity,当开启的 Activity 被销毁时会返回数据。
- setResult( int resultCode, Intent intent); 用于携带数据回传。
- onActivityResult( int requestCode, int resultCode, Intent data); 用于接收回传的数据。
startActivityForResult( Intent intent, int requestCode); 用于在 MainActivity 开启 SecondActivity。
setResult( int resultCode, Intent intent); 用于 SecondActivity 设置 Result,自身销毁后 Result 会返回到 MainActivity。
onActivityResult( int requestCode, int resultCode, Intent data); 用于对回传的 Result 解析,是在 SecondActivity 销毁后自动调用的。需要重写。
4.5 任务栈和启动模式
任务栈
任务栈是存放 Activity 实例的容器,销毁就弹出栈,用户操作的永远是栈顶。
启动模式
- standard 默认的启动模式,启动一个就创建一个新的实例。
- singleTop 如果启动的是栈顶的任务则复用,而不是创建新的实例。
- singleTask 如果启动的是栈内的任务则复用,而不是创建新的实例。
- singleInstance 启动新的栈来管理新的实例,不管哪个栈调用这个 Activity,整个系统里只有这一个 Activity,例如安卓的系统桌面。
4.6 Fragment (P95)
嵌入 Activity 的 UI 片段。
4.6.2 生命周期
受其所属的 Activity 影响,也和 Activity 类似,有 启动、运行、暂停、停止、销毁
五种状态,但 Activity 暂停,Fragment 也暂停,停止、销毁也是跟随 Activity 的。
在 Activity 运行的时候,可以单独对每个 Fragment 操作,如添加(启动状态)删除(销毁状态)等。
习题
一、填空题
- Activity 的启动模式包括 standard, singleTop,singleTask 和(singleintance)。
- 启动一个新的 Activity 并且获取这个 Activity 的返回教据,需要重写(startActivityForResult() )方法。
- 发送隐式 Intent 后,Android 系统会使用(IntentFilter)匹配相应的组件。
- 在清单文件中为 Activity 添加
<intent-filter>
标签时,必须添加的属性名为(action)否则隐式 Intent 无法开启该 Activity. - Activity 的(finish() )方法用于关闭当前的 Activity。
二、判断题
- 如果 Activity 不设置启动模式,则默认为 standard.√
- Fragment 与 Activity 的生命周期方法是一致的。× 方法当然不一样 P80 和 P95
- 如果想要关闭当前的 Activity, 可以调用 Activity 提供的 finish() 方法。√
<intent-filter>
标签中间只能包含一个 action 属性。× 多个- 默认情况下,Activity 的启动方式是 standard。√
三、选择题
- 下列选项中,不属于 Android 四大组件的是(C) A. Service B. Activity C. Handler D. ContentProvider
- 下列关于 Android 中 Activity 管理方式的描述中,正确的是(B) A. Android 以堆的形式管理 Activity B. Android 以栈的形式管理 Activity C. Android 以树的形式管理 Activity D. Android 以链表的形式管理 Activity
- 下列选项中,(B)不是 Activity 生命周期方法。 A. onCreate() B. startActivity() C. onStart() D. onResume()
- 下列方法中,(A)是启动 Activity 的方法。 A. startActivity() B. goToActivity() C. startActivityResult() D. 以上都是
- 下列关于 Intent 的描述中,正确的是(B) A. Intent 不能够实现应用程序间的数据共享 B. Intent 可以实现界面的切换,还可以在不同组件间直接进行数据传递 C. 使用显式 Intent 可以不指定要跳转的目标组件 D. 隐式 Intent 不会明确指出需要激活的目标组件,所以无法实现组件之间的数据跳转
第五章 数据存储
5 种存储方式:
- 文件存储 openFileInput() openFileOutput() 类似 Java。
- SharedPreferences 存储 存储一些简单的配置信息,采用 xml 格式。
- SQLite 数据库存储 支持基本 SQL 语法,一般使用其作为复杂数据的存储引擎。
- ContentProvider 四大组件之一,用于应用程序间的数据交换。可以将自己的数据共享给其它的应用程序使用。
- 网络存储 存储在网络服务器上。
5.2 文件存储(P108)
5.2.1 写入
内部存储
内部存储是存在应用程序中的,文件会被该应用程序私有化,其它应用程序需要申请权限才可以操作。卸载应用程序时,这些文件也会删除。
FileOutputStream fos = openFileOutput( String fileName, int mode);
String word = "Hello World!";
fos.write(word.getBytes());
fos.close();
写入( FileOutputStream
)有四种读写模式,以枚举的方式定义,填入第二个参数。
- MODE_PRIVATE只能被当前文件读写。
- MODE_APPEND可以追加。
- MODE_WORLD_READABLE该文件可以被其它程序读。
- MODE_WORLD_WRITEABLE可以被其它程序写。
外部存储
外部存储是存入外部的设备(SD卡或内嵌的存储卡)的。永久性的存储方式。可以被其它应用程序共享,可能会被浏览、修改、删除,是不安全的存储方式。
需要使用 Environment.getExternalStorageState()
方法确认外部设备是否可用。
String state = Environment.getExternalStorageState();
// 获取外存状态
if(state.equals(Environment.MEDIA_MOUNTED)) {
//状态判断
File SDPath = Environment.getExternalStorageDirectory();
// 获取 SD 卡路径
File file = new File( SDPath, "data.txt");
// 创建文件对象
FileOutputStream fos = new FileOutputStream(file);
// 打开文件流
fos.write( data.getBytes());
// 写入
fos.close();
// 关闭流
}
5.2.2 读取
内部存储
String content = "";
// 创建 存储的字符串
FileInputStream fis = openFileInput( "data.txt");
// 打开文件输入流
byte[] buffer = new byte[fis.available()];
// 创建缓冲区
fis.read(buffer);
// 读入缓冲区
content = new String( buffer);
// 读入字符串
fis.close();
//关闭流
外部存储
String state = Environment.getExternalStorageState();
// 获取外存状态
if(state.equals(Environment.MEDIA_MOUNTED)) {
//状态判断
File SDPath = Environment.getExternalStorageDirectory();
// 获取 SD 卡路径
File file = new File( SDPath, "data.txt");
// 创建对象文件
FileInputStream fis = new FileInputStream(file);
// 打开流
BufferedReader br = new BufferedReader( new InputStreamReader( fis));
// 创建字符输入缓冲流对象
String data = br.readLine();
// 读取数据
br.close();
fis.close();
}
5.3 SharedPreferences 存储(P115)
持久化存储。存一些配置,类似账号密码。采用 xml 格式。
5.4 SQLite 数据库存储(P118)
可以存储大量数据。
习题
一、判断题
- SQLite 是 Android 自带的一个轻量级的数据库,支持基本 SQL 语法。√
- Android 中的文件存储方式,分为内部存储方式和外部存储方式。√
- 使用 openFileOutput() 方式打开应用程序的输出流时,只需指定文件名。× 还有读写模式。这是内部存储的输出流,外存用
new FileOutputStream(file)
。Input 只要文件名(从文件里面读到程序里面当然不用什么追加什么的) - 当 Android SDK 版本低于 23 时,应用程序想要操作 SD 卡数据,必须在清单文件中添加权限。√
- SQLiteDatabase 类的 update() 方法用于删除数据库表中的数据。× update 当然是更新
- SQLite 数据库的事 务操作满足原子性、一致性、隔离性和持续性。√
二、选择题
- 下列关于 SharedPreferences 存取文件的描述中,错误的是(C)。 A. 属于移动存储解决方式 B. SharedPreferences 处理的就是 key-value 对 C. 读取 xml 的路径是 /sdcard/shared_prefs D. 文本的保存格式是 xml
- 下列选项中,不属于 getSharedPreferences 方法的文件操作模式参数是(B)。 A. Context.MODE_PRIVATE B. Context.MODE_PUBLIC C. Context.MODE_WORLD_ READABLE D. Context.MODE_WORLD_WRITEABLE
- 下列方法中,(B)方法是 shardPreferences 获取其编辑器的方法。 A. getEdit() B. edit() C. setEdit() D. getAll()
- Android 对教据库的表进行查询操作时,会使用 SQLietDatabase 中的(C)方法。 A. insert() B. execSQL() C. query() D. updata()
- 下列关于 SQLite 数据库的描述中,错误的是(C) A. SqliteOpenHelper 有创建数据库和更新数据库版本的的功能 B. SqliteDatabase 类是用来操作数据库的 C. 每次调用 SqliteDatabase 的 getWritableDatabase 方法时,都会执行 SqliteOpenHelper 的 onCreate() 方法 D. 当数据库版本发生变化时,会调用 SqliteOpenHelper 的 onUpgrade() 方法更新数据库
- 下列初始化 SharedPreferences 的内代码中,正确的是(D) A. SharedPreferences sp = new SharedPreferences(); B. SharedPreferences sp = SharedPreferences.getDefault(); C. SharedPreferences sp = SharedPreferences.Factory(); D. SharedPreferences sp = getSharedPreferences();
第六章 内容提供者和内容观察者
6.1 内容提供者
A 程序通过 ContentProvider 来暴露数据,B 程序通过 ContentResolve 操作 A 程序暴露的数据。A 程序会将操作结果返回给 ContentResolver,然后 ContentResolver 再将操作结果返回给 B。
两个重要的部分
- 数据模型 使用基于数据库模型的 简单表格,其中每个数据的唯一标识是
_ID
,数据类型是 int。查询字段数据用 getInt() /getString() /getLong() 等 - Uri ContentResolver 的增删查改方法以 Uri 的形式对外提供数据。 Uri 的三部分:
- scheme
content://
表示操作的数据被 ContentProvider 控制,不会被修改。 - authority 表示 ContentProvider 设置的唯一标识。主要用来区分程序,其一般是表示程序包名。
- path 表示资源或数据。可以动态修改。
content://
cn.itcast.mycontentprovider/
person
。 - scheme
6.4 内容观察者
实时监听 ContentProvider 共享的数据是否变化。
观察指定的 Uri 代表的数据的变化。
变化时触发 ContentObserver 的 onChange() 方法。
详细解释 P138
习题
一、判断题
- Uri 主要由三部分组成,分别是 scheme,authority 和 path。√
- 内容观察 ContentObserver 用于观察指定 URI 代表的数据的变化。√
- 内容提供者主要功能是实现跨程序共享数据的功能。√
- Android 中通过内容解析者查询短信数据库的内容时不需要加入读短信的权限。× 危险权限一共九个:
- 位置
- 日历
- 照相机
- 联系人
- 存储卡
- 传感器
- 麦克风
- 电话
- 短信 这九个需要动态申请。也就是说不仅需要在清单中注册,还需要在代码里面申请!
- Android 系统的 UriMatcher 类用于匹配 Uri。√
二、选择题
- 如果一个应用程序想要访问另外一个应用程序的数据库,那么需要通过(C)实现。 A. BroadcastReceiver B. Activity C. ContentProvider D. AIDL
- 下列方法中,(B)能够得到 ContentResolver 的实例对象。 A. new ContentResolver() B. getContentResolver() C. newInstance() D. ContentUris.newInstance()
- 自定义内容观察者时,需要继承的类是(B)。 A. BaseObserver B. ContentObserver C. BasicObserver D. DefalutObserver
- 对查询手机系统短信时,内容提供者对应的 Uri 为(C)。 A. Contacts.Photos.CONTENT_URI B. Contacts.People.CONTENT_URI C. content://sms/ D. Media.EXTERNAL_CONTENT_URI
- 下列关于 ContentProvider 的描述,错误的是(D)。 A. ContentProvider 是一个抽象类,只有继承后才能使用 B. ContentProvider 只有在 AndroidManifest.xml 文件中注册后才能运行 C. ContentProvider 为其他应用程序提供了统一的访问数据库的方式 D. 以上说法都不对
第七章 广播机制
7.1 广播机制的概述
广播机制:每个程序可以根据自己的兴趣来注册广播,广播可能是系统发送的也可能是其他应用发送的。
消息订阅者(广播订阅者)注册广播接收者(Binder 机制),广播发送者发送广播(Binder 机制),处理中心接收,根据消息发送者的要求,在已注册列表内寻找合适的消息订阅者,寻找依据是(IntentFilter/Permission)。然后由处理中心发送广播到消息订阅者。
广播接收者默认重写类的构造函数和 onReceive() 方法。
Android 8.0 后,必须用动态注册才可以接收广播,静态接收无效。
- 无序广播 异步执行,所有监听这个广播的广播接收者都会收到,但接收/执行顺序不确定。效率高,但无法拦截。
- 有序广播 按照广播接收者声明的优先级别依次接收,只有一个广播接收者能接收到。在这个广播接收者中的逻辑执行完,再继续传递。效率较低,有接收先后顺序,可以被拦截(终止)。优先级相同,先注册的先接收。
setPriority(int priority)
函数,参数值越大,优先级越高。 - 指定广播 有序广播的一种,保证某个接收者一定会接收到这个广播。
习题
一、填空题
- (BroadcastReceiver)用来监听来自系统或者应用程序的广播。
- 广播接收者的注册方式有两种,分别是(动态注册)和(静态注册)。
二、判断题
- Broadcast 表示广播,它是一种运用在应用程序之间传递消息的机制。√
- 在清单文件注册广播接收者时,可在
<intent-filer>
标签中使用 priority 属性设置优先级别,属性值越大优先级越高。√ - 有序广播的广播效率比无序广播更高。× 当然是无序的高,因为有序的需要按顺序接收和执行。
- 动态注册的广播接收者的生命周期依赖于注册广播的组件。√
- Android 中广播接收者必须在清单文件里面注册。× 动态注册不需要在清单里注册。但注意危险权限注册,既要在清单注册也要代码里面动态注册。
三、选择题
- 关于广播类型的说法,错误的是(BC)。(多选) A. Android 中的广播类型分有序广 播和无序广播 B. 无序广播是按照一定的优先级进行接收 C. 无序广播可以被拦截,可以被修改数据 D. 有序广播按照一定的优先级进行发送
- 广播作为 Android 组件间的通信方式,使用的场景有(ABCD)。(多选) A. 在同一个 APP 内部的同一组件内进行消息通信 B. 不同 APP 的组件之间进行消息通信 C. 在同一个 APP 内部的不同组件之间进行消息通信(单个进程) D. 在同一个 APP 具有多个进程的不同组件之间进行消息通信
第八章 服务
8.1 服务概述
四大组件之一,关于四大组件见 1.4。
在后台长时间执行操作并且不提供用户界面的应用程序。
一般由 Activity 启动,但不依赖于 Activity,有自己的生命周期。
应用场景:
- 后台运行 后台长时间运行而不提供界面,系统必须回收内存资源的时候,会被销毁,否则一直在后台运行。
- 跨应用访问 服务被启动时,即使用户切换到其它应用程序,服务也会后台继续运行
例如多媒体后台播放是服务,后台记录地理位置也是服务。
注意,服务并不是运行在子线程中,而是在主线程中,只是没有界面而已。它的耗时操作会开启子线程来处理,否则会出现 ANR(程序无响应)异常。
8.3 服务的生命周期
与启动方式有关,有两种启动方式。
startService()
方法(其他组件调用stopService()
停止,服务自身调用stopSelf()
) 依次调用onCreate()
onStartCommand()
onDestory()
在后台长时间运行,启动服务的组件与服务之间没有关联。即使组件被销毁,服务也会继续运行。bindService()
方法(unbindService()
解绑) 依次调用onCreate()
onBind()
onUnbind()
onDestory()
服务与组件绑定,允许组件与服务交互,组件退出/调用unbindService()
方法,服务就会销毁(当所有组件都解绑的时候,这个服务就会被销毁)。 多个组件可以绑定一个服务。第一个组件绑定是会回调onCreate()
生命周期方法,后续的绑定只会调用onBind()
方法,返回 IBinder 给客户端。
8.5 服务的通信
通过调用 bindService()
方法开启服务后,服务与绑定服务的组件之间可以通信,通过组件可以控制服务操作服务。
通信可以先用 startService()
来开启服务,再 bind
绑定组件来通信,也可以直接以 bindService()
来开启服务。
服务通信方式有两种
- 本地服务通信 应用程序内部通信。
Service 类
的onBind()
方法会返回一个IBinder 对象
,传递给ServiceConnection 类
的onServiceConnected( ComponentName Name, IBinder service)
方法,然后绑定服务的组件就通过IBinder 对象
与Service
通信。 - 远程服务通信 应用程序之间的通信。通过
AIDL(一种接口定义语言)
实现。由于每个应用程序都有自己的进程,因此远程服务通信,是不同进程之间的通信。注意进程与线程的区别,线程是更小的概念,前面提到后台服务在主线程内,耗时操作在子线程内。而主线程和子线程都在进程内。
习题
一、填空题
- 如果想要停止
bindService()
方法启动的服务,需要调用(onUnbind()
)方法。 - Android 系统的服务的通信方式分为(本地通信)和(远程通信)。
- 远程服务通过(AIDL)实现服务的通信。
二、判断题
- Service 服务是运行在子线程中的。× 是主线程,但耗时操作放到子线程,否则出现程序无响应。
- 不管使用哪种方式启动 Service, 它的生命周期都是一样的。× 生命周期的方法都不一样,生命周期也不一样
- 使用服务的通信方式进行通信时,必须保证服务是以绑定的方式开启的,否则无法通信。√
- 一个组件只能绑定一个服务。× 多个组件可以绑定一个服务,一个组件可以绑定多个服务(据说)
- 远程服务和本地服务都运行在同一个进程中。× 远程服务是不同进程之间的数据通信,因此是多进程。
三、选择题
- 如果通过 bindService 方式开启服务,那么服务的生命周期是(C)。 A. onCreate() →onstart() →onBind() →onDestroy() B. onCreate() →onBind() →onDestroy() C. onCreate() →onBind() →onUnBind() →onDestroy() D. onCreate() →onStart() →onBind() →onUnBind() →onDestroy()
- 下列关于 Service 服务的描述中,错误的是(D) A. Service 是没有用户可见的界面,不能与用户交互 B. Service 可以通过 Context.startService() 来启动 C. Service 可以通过 Context.bindService() 来启动 D. Service 无须在清单文件中进行配置
- 下列关于 Service 的方法描述,错误的是(D)。 A. onCreate() 表示第一次创建服务时执行的方法 B. 调用 startService() 方法启动服务时执行的方法是 onStartCommand() C. 调用 bindService() 方法启动服务时执行的方法是 onBind() D. 调用 startService() 方法断开服务绑定时执行的方法是 onUnbind()