9.四大组件的工作过程
Android的四大组件除了BroadcastReceiver以外,其他三种组件都必须在AndroidManifest中注册,对于BroadcastReceiver来说,它既可以在AndroidManifest中注册也可以通过代码注册。在调用方式上,Activity、Service和BroadcastReceiver需要借助Intent,而ContentProvider则无需借助Intent。
Activity是一种展示型组件,用于向用户直接地展示一个界面,并且可以接收用户的输入信息从而进行交互。Service是一种计算型组件,用于在后台执行一系列计算任务。BroadcastReceiver是一种消息型组件,用于在不同的组件乃至不同的应用之间传递消息。广播注册有两种方式:静态注册和动态注册。静态注册是指在AndroidManifest中注册广播,这种广播在应用安装时会被系统解析,此种形式的广播不需要应用启动就可以收到相应的广播。动态注册广播需要通过Context.registerReceiver()来实现,并且在不需要的时候要通过Context.unregisterReceiver()来解除广播,此种形态的广播必须要应用启动才能注册并接收广播,因为应用不启动就无法注册广播,无法注册广播就无法收到相应的广播。ContentProvider是一种数据共享型组件,用于向其他组件乃至其他应用共享数据。对于一个ContentProvider组件来说,它的内部需要实现增删改查这四种操作,在它的内部维持着一份数据集合,这个数据集合既可以通过数据库来实现,也可以采用其他任何类型来实现,比如List和Map,ContentProvider对数据集合的具体实现并没有任何要求。需要注意的是,ContentProvider内部的insert、delete、update和query方法需要处理好线程同步,因为这几个方法是在Binder线程池中被调用的。
ContextImpl是通过Activity的attach方法来和Activity建立关联的,除此以外,在attach方法中Activity还会完成Window的创建并建立自己和Window的关联,这样当Window接收到外部输入事件后就可以将事件传递给Activity。
系统首先从mPackageInfo获取IIntentReceiver对象,然后再采用跨进程方式向AMS发送广播注册的请求。之所以采用IIntentReceiver而不是直接采用BroadcastReceiver,这是因为上述注册过程是一个进程间通信的过程,而BroadcastReceiver作为Android的一个组件是不能直接跨进程传输的,所以需要通过IIntentReceiver来中转一下。毫无疑问,IIntentReceiver必须是一个Binder接口,它的具体实现是LoadApk.ReceiverDispatcher.InnerReceiver,ReceiverDispatcher的内部同时保存了BroadcastReceiver和InnerReceiver,这样当接收到广播时,ReceiverDispatcher可以很方便地调用BroadcastReceiver的onReceive方法。可以发现,BroadcastReceiver的这个过程和Service的实现原理类似,Service也有一个叫ServiceDispatcher的类,并且其内部类InnerConnection也是一个Binder接口,作用同样也是为了进程间通信。
当ContentProvider所在的进程启动时,ContentProvider会同时启动并被发布到AMS中,需要注意的是,这个时候ContentProvider的onCreate要先于Application的onCreate而执行。
当一个应用启动时,入口方法为ActivityThread的main方法,main方法是一个静态方法,在main方法中会创建ActivityThread的实例并创建主线程的消息队列,然后在ActivityThread的attach方法中会远程调用AMS的attachApplication方法并将ApplicationThread对象提供给AMS。ApplicationThread是一个Binder对象,它的Binder接口是IApplicationThread,它主要用于ActivityThread和AMS之间的通信。在AMS的attachApplication方法中,会调用ApplicationThread的bindApplication方法,bindApplication的逻辑会经过ActivityThread中的mH Handler切换到ActivityThread中去执行,具体的方法是handleBindApplication。在handleBindApplication方法中,ActivityThread会创建Application对象并加载ContentProvider。
ContentProvider启动后,外界就可以通过它锁提供的增删改查这四个接口来操作ContentProvider中的数据源,即insert、delete、update、query四个方法。这四个方法都是通过Binder来调用的,外界无法直接访问ContentProvider,它只能通过AMS根据Uri来获取对应的ContentProvider的Binder接口IContentProvider,然后再通过IContentProvider来访问ContentProvider中的数据源。
通过AMS来访问ContentProvider,这里的ContentProvider不是原始的ContentProvider,而是ContentProvider的Binder类型的对象IContentProvider,IContentProvider的具体实现是ContentProviderNative和ContentProvider.Transport,其中ContentProvider.Transport继承了ContentProviderNative。