前言
本文已经收录到我的
Github
个人博客,欢迎大佬们光临寒舍:
学习清单:
Activity
的工作过程Service
的工作过程
Service
的启动过程Service
的绑定过程
BroadcastReceiver
的工作过程
BroadcastReceiver
的注册过程BroadcastReceiver
的发送和接收过程
ContentProvider
的工作过程
一.为什么要学习四大组件?
何为“四大”:
Activity
Service
BroadcastReceiver
ContentProvider
谈到四大组件,相信在座各位都再熟悉不过了,光闻其名,未见其声,“四大”二字一出,足见其在安卓系统中的地位,可谓是安卓界的F4
。
其地位之崇高,在某种程度上也可以体现他的重要性,所以说,光会使用四大组件还是不能体现我们对他的重视(ai hu)的,我们还要分析其工作过程,能够更好地理解系统内部的运行机制,从而加深对Android
体系结构的认识;同时,四大组件还是面试必问的知识点之一。
综上,掌握好四大组件相关的知识,对于一个Android
开发者来说是非常重要的!
以下内容紧张赤鸡,请系好保险带,我们要开车(hu you)了。— No picture,say a J8!
二.核心知识点归纳
2.1 概述
2.1.1 Activity
-
类型:展示型组件
-
作用:展示一个界面并和用户交互
-
使用:
A.需要在
AndroidManifest
中注册B.需要借助
Intent
启动,两种方式:
显示
Intent
:
Intent intent=new Intent(xxx.this,xxx.class); startActivity(intent);
隐式
Intent
:
Intent intent=new Intent(); intent.setAction(xxx); intent.addCategory(xxx); startActivity(intent);
- 四种启动模式:
standard
:标准模式singleTop
:栈顶复用模式singleTask
:栈内复用模式singleInstance
:单实例模式想了解启动模式的读者,可以看下笔者写的一篇文章:进阶之路 | 奇妙的Activity之旅中的
2.2
部分
- 通过
finish()
结束一个Activity
2.1.2 Service
-
类型:计算型组件
-
作用:在后台执行一系列计算任务,耗时的后台计算建议在单独的线程中执行
-
使用:
A.需要在
AndroidManifest
中注册B.需要借助
Intent
启动:Intent intent = new Intent(xxx.this, xxx.class); startService(intent);
C.两种运行状态:
- 启动状态:通过
startService()
- 绑定状态:通过
bindService()
D.停止方式:unBindService();stopService();
2.1.3 BroadcastReceiver
- 类型:消息型组件
- 作用:在不同的组件乃至不同的应用之间传递消息
- 使用:
两种注册方式:
A.动态注册:通过
Context.registerReceiver()
&Context.unRegisterReceiver()
,必须要启动应用才能注册并接收广播。B.静态注册:在
AndroidManifest
文件中注册,不需要启动应用即可接收广播。需要借助
Intent
发送广播:Intent intent = new Intent("xxx"); sendBroadcast(intent);
四种广播类型:
A.普通广播
B.有序广播
C.本地广播
D.粘性广播
- 没有停止概念
2.1.4 ContentProvider
- 类型:共享型组件
- 作用:向其他组件乃至其他应用共享数据(安卓
IPC
的一种方式) - 使用:
需要在
AndroidManifest
中注册无需借助
Intent
启动四种操作:注意需要处理好线程同步(因为这些操作运行在
Binder
线程)A.
insert()
:添加数据B.
update()
:更新数据C.
delete()
:删除数据D.
query()
:查询数据
- 无需手动停止
想详细了解
IPC
机制的读者,可以看下笔者写的一篇文章:进阶之路 | 奇妙的 IPC 之旅
2.2 工作过程
差不多该进入今天的主题了,为了逼格,为了高薪,大伙往前冲!
2.2.1 Activity
Activity
启动过程流程图:
一眼看上去有点晕晕的,墙裂建议配合源码一起服用,效果极佳,笔者推荐一篇文章:图解Activity启动流程,进阶高级
Q1:结论:
ActivityManagerService
、ApplicationThread
都是Binder
Application
的创建也是通过Instrumentation
来完成的,这个过程和Activity
对象一样,都是通过类加载器来实现的Activity
的启动过程最终回到ApplicationThread
中,通过ApplicationThread.scheduleLaunchActivity()
将启动Activity
的消息发送并交由Handler H
处理。Handler H
对消息的处理会调用handleLaunchActivity()
->performLaunchActivity()
得以最终完成Activity的创建和启动。
Q2:重点类:
Instrumentation
:
instrumentation
是Android
系统里面的一套控制方法或者”钩子“。 这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android
控件的运行;它们同时可以控制Android
如何加载应用程序。
ActivityManagerService「AMS」
:
AMS
是系统的引导服务,应用进程的启动、切换和调度、四大组件的启动和管理都需要AMS
的支持。
ActivityStackSupervisor
:
ActivityStackSupervisor
在AMS
中的构造方法中被创建。
AMS
通过操作ActivityStackSupervisor
来管理Activity
ActivityStack
:
ActivityStack
从名称来看是跟栈相关的类,其实它是一个管理类,用来管理系统所有Activity
的各种状态- 它由
ActivityStackSupervisor
来进行管理的
ApplicationThread
:
ActivityThread
的私有内部类,也是一个Binder
对象- 在此处它是作为
IApplicationThread
对象的Server
端,等待Client
端的请求然后进行处理,最大的Client
就是AMS
2.2.2 Service
源码流程分析:Service的工作过程
1.启动过程:
2.绑定过程:
结论:
ContextImpl
是Context
的具体实现,通过Activity.attach()
和Activity
建立关联。Activity.attach()
中还会完成Window
的创建并和Activity&Window
的关联,由此事件可传递给Window
。ActivityServices
是一个辅助ActivityManagerService
(AMS)进行Service
管理的类,包括Service
的启动、绑定和停止。- 和
Activity
类似的,Service
的启动/绑定过程最终回到ApplicationThread
中,通过ActivityThread.handleCreateService()
/ActivityThread.handleBindService
完成Service的启动/绑定,注意绑定Service的后续还必须告知客户端已经成功连接Service
的这一流程,由ActivityManagerService.publishService()
去完成。
2.2.3 BroadcastReceiver
源码流程分析:BroadcastReceiver 的工作过程分析
1.注册
四大组件的静态注册都是在应用安装时由
PackageManagerService(PMS)
解析注册,当动态注册BroadcastReceiver
时流程为:
2.发送和接收
结论:
- 动态注册广播最终会跨进程交给
AMS
,并把远程Receiver
( 实际上传的是IIntentReceiver
,是个Binder
对象)和远程IntentFilter
保存起来,完成注册任务 - 发送广播时,系统为intent添加了两个标记位:
FLAG_EXCLUDE_STOPPED_PACKAGES
:广播不会发送给已经停止的APP
(系统为所有广播默认添加该标记)FLAG_INCLUDE_STOPPED_PACKAGES
:广播也会发送到已经停止的APP
(两个标记共存时,以该标记为准)
- 最终在
ReceiverDispatcher .performReceive ()
里回调了Receiver
的onReceive()
,使得广播得以接收并处理
Q2:实现原理:
从实现原理看上,广播使用了观察者模式,基于消息的发布/订阅事件模型
具体实现流程要点粗略概括如下:
- 广播接收者
BroadcastReceiver
通过Binder
机制向AMS
进行注册 - 广播发送者通过
Binder
机制向AMS
发送广播 AMS
查找符合相应条件(IntentFilter
/Permission
等)的BroadcastReceiver
,将广播发送到BroadcastReceiver
(一般情况下是Activity
)相应的消息循环队列中- 消息循环执行拿到此广播,回调
BroadcastReceiver
中的onReceive()
方法
2.2.4 ContentProvider
1.启动流程总概
- 启动的入口为
ActivityThread.main()
:创建ActivityThread
实例并创建主线程消息队列 ActivityThread.attach()
:远程调用AMS.attachApplication()
并提供ApplicationThread
用于和AMS
的通信AMS.attachApplication()
:通过ActivityThread.bindApplication()
方法和Handler H
来调回ActivityThread.handleBindApplication()
ActivityThread.handleBindApplication()
:先创建Application
、再加载ContentProvider
、最后回调Application.onCreate()
2.Query
过程流程
insert()
、delete()
和update()
的实现原理和query()
类似,限于篇幅,这里不展开,感兴趣的读者可以主动去探究源码流程分析:ContentProvider的工作过程
结论:
-
ContentProvider
的multiprocess
属性:ContentProvider
是否是单例,一般用单例 -
访问
ContentProvider
需要ContentResolver
,其真正实现类是ApplicationContentResolver
。当ContentProvider
所在进程未启动时,第一次访问它会触发ContentProvider
的创建以及进程启动 -
当
ContentProvider
所在的进程启动时,会同时被启动并被发布到AMS
中
注意:
ContentProvider.onCreate()
要先于Application.onCreate()
执行
- 同样的,最终通过
ActivityThread.handleBindApplication()
完成ContentProvider
的创建。
三.课堂小测试
恭喜你!已经看完了前面的文章,相信你对
四大组件
已经有一定深度的了解,下面,进行一下课堂小测试,验证一下自己的学习成果吧!
Q1:为什么要使用ContentProvider
?它和SQL
在实现上有什么区别?
ContentProvider
屏蔽了数据存储的细节,内部实现透明化,用户只需关心URI
即可(是否匹配)ContentProvider
能实现不同APP
的数据共享,SQL
只能是自己程序才能访问ContentProvider
还能增删本地的文件,XML
等信息
Q2:Android
引入四大组件的用意
这个问题在笔者刚开始学习
Android
的时候就一直困惑,直到看了一篇Google Android 团队:Dianne Hackborn发表在Google+
上的一篇post
的译文
见解:Google Android Framework
团队决定,不要让一个明确的Main
方法作为APP
的入口,因为需要让系统对APP
怎样运行有更多的控制权,在该系统中,用户永远不需要考虑开启和停止一个APP
,而把这些事交给系统去管理。所以他们设计了四大组件以作为APP
功能的载体和入口:
Activity
一个
APP
与用户交互的入口
BroadcastReceiver
- 一种让系统在正常的用户流(
user flow
)之外,传递事件给APP
的机制。- 最重要的是,因为这是另一个被精心定义的
APP
的入口,即使APP
当前并不在运行,系统也可以将Broadcasts
传递给APP
。
Service
当
APP
由于各种各样的原因需要在后台运行时,Service
就是一个这样的入口
ContentProvider
- 人们通常会将它当作对数据库的抽象,因为有许多的
API
和支持库就是这样使用ContentProvider
的- 但是从系统设计的角度,这并不是
ContentProvider
的初衷。对于系统来说,ContentProvider
实际上是一个入口,用于获取一个APP
内部的公开的被命名的数据项(data items
),每个数据项都被一个URI scheme
所标识。
如果文章对您有一点帮助的话,希望您能点一下赞,您的点赞,是我前进的动力
本文参考链接: