开发艺术探索 -- 四大组件的工作过程

第九章,四大组件的工作过程

四大组件的运行状态
Activity的工作过程
Service的工作过程
BroadCastReceiver工作过程
ContentProvider工作过程

  • Activity

    1. 除了BroadCastReceiver外,都必须在Manifest中注册.BroadCastReceiver可以通过代码或Manifest注册,
    2. 调用方式上除了ContentProvider外,其他组件都需要借助Intent
    3. Intent分为显示Intent和隐式Intent.
    4. Activity主要用来展示一个界面和用户交互
  • Service

    1. 一种计算型组件.用于在后台执行一系列计算任务
    2. Service启动状态和绑定状态
    3. Service是运行在主线程的,耗时的后台任务需要开线程
    4. 处于绑定状态的Service,外界可以很方便的和其进行通信
    5. Service可以通过stopServiceunBindService停止
  • BroadCastReceiver
    1. 一种消息型组件
    2. 广播的注册有两种方式,静态注册动态注册(需要绑定和解绑)
    3. 动态注册的广播需要应用启动才能注册并接受广播
    4. 广播可以实现低耦合的观察者模式,广播没有停止的概念
  • ContentProvider
    1. 数据共享型组件
    2. ContentProvider可以通过数据库实现,也可以通过其他方式来实现
    3. ContentProvider除了onCreate外都运行在Binder线程池,需要做好同步
    4. ContentProvider不需要停止

Activity工作过程

Activity#startActivityForResult
-> Instrumentation#execStartActivity
-> ActivityManagerNative.getDefault().startActivity(AMS#startActivity)
//ActivityManagerNative继承自Binder并实现了IActivityManager
//ActivityManagerService 继承了ActivityManagerNative,上面的getDefault是通过单例获取到的AMS

除了调用Instrumentation.execStartActivity除了上面的会调用AMS.startActivity外,还会检查启动Activity的结果.比如常见的清单文件没有注册就是在此抛出的.

AMS#startActivity -> ActivityStackSupervisor#startActivityMayWait
-> .. -> ActivityStack#resumeTopActivitiesLocked 
-> .. -> ActivityStackSupervisor#realStartActivityLocked

如上经过一系列调用,最终调用到了ActivityStackSupervisor#realStartActivityLocked方法,进而调用app.thread#scheduleLaunchActivity.

其中app.thread的类型为IApplicationThread,其申明如下:

public interface IApplicationThread extends IInterface

IApplicationThread是一个Binder,内部完成了大量Activity和Service生命周期操作.其实现类是ActivityThread.ApplicationThread,其申明如下:

private class ApplicationThread extends ApplicationThreadNative{
//...
}
public abstract class ApplicationThreadNative extends Binder
        implements IApplicationThread{
        //和系统生成的AIDL文件作用一致.内部有一个ApplicationThreadProxy类,由于此类是抽象类,故ApplicationThread就成了IApplicationThread的最终实现类
        }

绕了一大圈,最终是ApplicationThread.scheduleLaunchActivity启动Activity.

//ApplicationThread#scheduleLaunchActivity
//通过发送消息来启动Activity
 sendMessage(H.LAUNCH_ACTIVITY, r);

这个 H 是 ActivityThread 的内部类.继承了Handler

// H#handleMessage
public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
//...
                    handleLaunchActivity(r, null);
                } break;
//ActivityThread#handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent){
//
 Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
// 调用Activity.onResume生命周期方法/
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
}
}

其中,performLaunchActivity主要完成了如下几件事

  1. ActivityClientRecord中获取待启动的Activity
  2. 通过Instrumentation.newActivity方法用类加载器加载Activity对象
  3. 通过LoadedApk.makeApplication尝试创建Application对象.(如果已创建,则不会重复创建),进而回调Application#onCreate.
  4. 创建ContextImpl,并调用Activity#attach完成一些重要数据的初始化.(ContextImpl通过attach来和Activity建立关联,并且在attach中完成window的创建,并建立Activitywindow的关联)
  5. 调用Activity#onCreate方法.

Service工作过程

Service启动过程

contextImpl#startService -> contextImpl#startService
-> ActivityManagerNative.getDefault().startService(AMS#startService)
-> mServices#startServiceLocked

mServices是ActiveService类型,是辅助AMS进行Service管理的类.

// 经过一系列的调用,最终调用到了realStartServiceLocked
mServices#startServiceLocked -> ...-> realStartServiceLocked.
// 如下两个过程都是IPC过程
realStartServiceLocked -> app.thread#scheduleCreateService(H.sendMessage) 
-> Service#onCreate -> sendServiceArgsLocked 
-> onStartCommand
  1. 如上的app.thread即 ActivityThread.ApplicationThread,调用过程类似,依旧是调用H.sendMessage完成Service的启动
  2. ContextImpl通过Service#attach建立二者之间的联系.
  3. activity#handleServiceArgs调用Service#onStartCommand

Service绑定过程

contextImpl#bindServie -> contextImpl#bindService ->bindServiceCommon

其中bindServiceCommon做了两件事
1. 将客户端ServiceConnection转化为ServiceDispatcher.InnerConnection对象.转化是因为服务端的绑定时垮进程的,InnerConnection刚好充当了Binder的角色,ServiceDispatcher连接着InnerConnectionServiceConnection,系统会通过InnerConnection调用ServiceConnection#onServiceConnected.
2. 通过AMS完成Service的具体绑定过程.

AMS#bindService -> ActiveServices#bindServiceLocked 
-> realStartServiceLocked //后续过程和Service启动过程类似
-> app.thread#scheduleBindService 
-> sendMessage(H.BIND_SERVICE, s)

Handler 接受到消息后,会调用 handleBindService,根据Service的Token取出Service,并调用Service#onBind,完成绑定.然而此时客户端并不知道已经连接上了,通过AMS#publishService需要回调onServiceConnected通知客户端.

需要注意的是:
1. 对于同一服务, ServiceonBindonCreate 都只会执行一次.
2. ServiceConnection在主线程被回调.其 是一个Runnable,最终会调用 onServiceConnected

BroadCastReceiver工作过程

广播注册
广播发送和接收

广播的注册

静态注册的广播在应用安装时由系统自动完成注册,即有PMS 来完成
其他三大组件也是通过PMS解析清单文件来完成注册的.

  • 广播的动态注册
contextImpl#registerReceiverInternal
//首先,从mPackageInfo中获取IIntentReceiver,然后跨进程向AMS发送广播注册的请求
//之后调用AMS#registerReceiver
-> ActivityManagerNative.getDefault().registerReceiver
  1. IIntentReceiver是一个Binder对象,具体实现类是LoadedApk.ReceiverDispatcher.InnerReceiver
    和Service类似,ReceiverDispatcher内部同时保存了BroadCastReceiverInnerReceiver,
  2. AMS#registerReceiver看起来很长,关键部分就是把远程的InnerReceiver与IntentFilter对象存储起来,如下所示
 public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
            //...
             mRegisteredReceivers.put(receiver.asBinder(), rl);
             //...
             mReceiverResolver.addFilter(bf);
        }

广播的发送和接收

  1. send后,AMS查找出匹配的广播接收者,并将广播发送给他们处理
  2. 广播的发送类型: 普通广播,有序广播,粘性广播
  3. 广播的发送接收本质是一个过程的两个阶段
contextImpl.sendBroadcast -> ActivityManagerNative.getDefault().broadcastIntent
//向AMS发起一个异步请求发送广播
-> AMS#broadcastIntentLocked

这里有个点需要注意,
1. 从3.1开始,默认情况下广播不会发给已经停止的应用
2. 在3.1中已经加入了两个标志位用于控制是否对停止状态应用起作用
FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已停止应用
FLAG_INCLUDE_STOPPED_PACKAGES:包含已停止应用,两种状态共存时,选择包含
3. 应用停止分为两种:1. 安装未运行,2.被强停了
4. 这个特性会影响开机广播

//根据 intent-filter找出匹配的,添加到BroadcastQueue中,然后发送给接收者
AMS#broadcastIntentLocked->BroadcastQueue.scheduleBroadcastsLocked()
//遍历所有广播,并发送给接收者
-> mHandler.sendMessage -> processNextBroadcast 
->... ->
//具体的发送过程
performReceiveLocked

performReceiveLocked内部依然会调用app.threadscheduleRegisteredReceiver

scheduleRegisteredReceiver -> InnerReceiver.performReceive 
-> LoadedApk.ReceiverDispatcher.performReceive 
-> ActivityThread.post(Args)

其中ActivityThread就是H,Args实现了Runnable,Args的run方法中有如下代码片段:

 final BroadcastReceiver receiver = mReceiver;
 receiver.setPendingResult(this);
 receiver.onReceive(mContext, intent);

ContentProvider工作过程

ContentProvideronCreate要先于Application的onCreate执行.

  1. 当应用启动时,入口方法是Activity#main
  2. main方法中会创建主线程消息队列
  3. ActivityThread#attach远程调用AMS#attachApplication,并将ApplicationThread对象提供给AMS
  4. AMS#attachApplication会调用ApplicationThread#bindApplication
  5. ApplicationThread#bindApplication会经过ActivityThread.mH切换到ActivityThread中执行.具体方法就是handleBindApplication
  6. handleBindApplication中,ActivityThread会创建Application对象,并加载ContentProvider
  7. ActivityThread会先加载ContentProvider,后回调Application#onCreate
  1. 一般来说,ContentProvider应该是单实例的,具体需要有它的android:multiprocess属性决定.(默认为false)
  2. 如果此属性为true,则每个调用者进程中都存在一个ContentProvider对象
  3. 多实例场景很少.可以 简单认为Contentprovider都是单实例的

访问Contentprovider需要通过ContentResolver(抽象类),通过contex t.getContentResolver获取的是ApplicationContentResolver对象.

  • ContentProvider的query操作

这里以查询操作为例.首先会通过acquireProvider来获取IContentProvider

ApplicationContentResolver#acquireProvider 
//如果没有ContentProvider启动,就会跨进程请求AMS启动ContentProvider
-> ActivityThread#acquireProvider

启动ContentProvider,首先会启动其所在的进程.启动进程由AMS#startProcessLocked完成.

AMS#attachApplication ->ActivityThread#bindApplication(/*通过发送消息给mH*/) 
-> //完成Application及ContentProvider的创建

具体步骤如下:

  1. 创建ContextImplInstrumentation
  2. 创建Application
  3. 启动ContentProvider并调用其onCreate
  4. 调用Application#onCreate
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值