进阶之路 | 奇妙的四大组件之旅
前言
本文已经收录到我的
Github个人博客,欢迎大佬们光临寒舍:
学习清单:
Activity的工作过程Service的工作过程
Service的启动过程Service的绑定过程
BroadcastReceiver的工作过程
BroadcastReceiver的注册过程BroadcastReceiver的发送和接收过程
ContentProvider的工作过程
一.为什么要学习四大组件?
何为“四大”:
ActivityServiceBroadcastReceiverContentProvider
谈到四大组件,相信在座各位都再熟悉不过了,光闻其名,未见其声,“四大”二字一出,足见其在安卓系统中的地位,可谓是安卓界的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都是BinderApplication的创建也是通过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所标识。
如果文章对您有一点帮助的话,希望您能点一下赞,您的点赞,是我前进的动力
本文参考链接:

谈到四大组件,相信在座各位读者再熟悉不过了,光闻其名,未见其声,“四大”二字一出,足见其在安卓系统中的地位,可谓是安卓界的F4。
浙公网安备 33010602011771号