Android四大组件的工作过程,原明确析

源码 2024-9-20 21:24:21 141 0 来自 中国
一、Activity启动过程


    起首我们要知道Activity有冷启动和热启动之分,平凡来说冷启动就是应用历程尚未创建,热启动则已经创建完成。
    在点击桌面应用图标时,即将要启动的App将和Launcher、AMS、Zygote这三者多次通讯,才会启动一个App,然后再启动Activity。
追踪源码,我们可以得到以下团体的时序图:
简朴的梳理下团体流程,我们可以直接得到以卑鄙程:
Launcher历程通过Binder机制通知AMS
AMS则判断应用历程是否已经存在(冷启动),不存在则通过Socket通讯通知Zygote历程fork应用历程,已经启动(热启动)则无需再次创建App历程。
应用历程创建完成之后则会通过Binder机制通知AMS 创建完成。
AMS通过Binder机制哀求ApplicationThread创建并启动根Activity。
ApplicationThread通过Handle机制通知主线程ActivityThread,终极调用到根Activity的onCreate、onStart、onResume等方法完成创建。
二、Service的启动过程


    Service的启动照旧和Activity有许多相似处的,都须要和AMS打招呼。
    众所周知,Service的启动有两种方式一种StartService,一种bindService,那它们的启动过程是否一样呢?带着疑惑我们往下看。
    起首我们看StartService,直接分析源码,可以得到以下时序图:
4.png     注:1.bringUpServiceLocked方法调用时,此中启动Service时会判断app==null,app的范例是ProcessRecord,用来形貌运行的应用步调历程的信息,在此中将Service运行的历程名和uid转达给ActivityManagerService的getProcessRecordLocked方法,从而获取运行Service的应用步调历程信息ProcessRecord,假如用来运行Service的应用步调历程不存在,就会调用ActivityManagerService的startProcessLocked方法来创建对应的应用步调历程;假如用来运行Service的应用步调历程存在,会调用realStartServiceLocked方法。
    2.H是ActivityThread的内部类并继承自Handler,AMS通过IApplicationThread向应用步调历程发送消息,担当消息的操作是在应用步调历程的Binder线程池中举行,因此须要Handler来发送消息切换到主线程。
    总结下来就是
    下面接着分析下bindService,它的流程会相对startService复杂一丢丢,照例直接分析源码,可以得到以下时序图:
    大抵总结一下就是应用历程这边调用一系列方法终极与AMS通讯bindService,然后AMS中调用activeService类中的方法,然后又通过ApplicationThread与应用历程这边通讯handleBindService,然后通知AMS去publishService,调用的activeService的publishServiceLocked方法,此中调用了ServiceDispatcher.InnerConnection的connected方法,再调用ServiceDispatcher的connected方法,ServiceDispatcher是LoadedApk的内部类,并调用Handler范例的对象mActivityThread的post方法,mActivityThread实际指向的是ActivityThread的内部类H,终极通过H类的post方法将RunConnection对象的内容运行在主线程中,RunConnections是LoadedApk的内部类,末了调用mConnection的onServiceConnected,mConnection的范例是ServiceConnection,这样客户端实现ServiceConnection接口类的onServiceConnected方法就会被调用。
三、BroadcastReceiver的注册、发送和吸收


   广播注册分为动态注册和静态注册,起首我们分析动态注册。
    动态注册的过程是从ContextWrapper#registerReceiver()开始的. 和Activity大概Service一样. ContextWrapper并没有做实际的工作, 而是将注册的过程直接交给了ContextImpl来完成。
    ContextImpl#registerReceiver()方法调用了本类的registerReceiverInternal()方法。
    体系起首从mPackageInfo获取到IIntentReceiver对象, 然后再采用跨历程的方式向AMS发送广播注册的哀求. 之所以采用IIntentReceiver而不是直接采用BroadcastReceiver, 这是由于上述注册过程中是一个历程间通讯的过程. 而BroadcastReceiver作为Android中的一个组件是不能直接跨历程转达的. 所以须要通过IIntentReceiver来实现通讯。
    IIntentReceiver作为一个Binder接口, 它的详细实现是LoadedApk.ReceiverDispatcher.InnerReceiver, ReceiverDispatcher的内部同时生存了BroadcastReceiver和InnerReceiver, 这样当吸收到广播的时间, ReceiverDispatcher可以很方便的调用BroadcastReceiver#onReceive()方法. 这里和Service很像有同样的类, 而且内部类中同样也是一个Binder接口。
    由于注册广播真正实现过程是在AMS中, 因此跟进AMS中, 起首看registerReceiver()方法, 这里只关心田面的核心部分. 这段代码终极会把长途的InnerReceiver对象以及IntentFilter对象存储起来, 这样整个广播的注册就完成了。
8.png 静态注册的过程就比力简朴
1.AndroidManifest.xml中的receiver剖析成ParsedActivity, 存放在PackageImpl的receivers(PackageImpl父类是ParsingPackageImpl而且实现了AndroidPackage接口)
2.receivers终极会存放在mComponentResolver(PMS)的mReceivers中,mReceivers包罗了全部安装应用的receiver,通过ComponentName就可以得到相应的ParsedActivity,如:
3.mReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceive”)),既可以得到MyReceiver的ParsedActivity
4.receiver中的一个IntentFilter(intent-filter)对应一个ParsedIntentInfo,一个Pair<arsedActivity, ParsedIntentInfo>
5.Pair<arsedActivity, ParsedIntentInfo>被放入mComponentResolver的mFilters
6.mActions被放入mComponentResolver的mActionToFilter
    部分静态广播注册须要权限,不是注册了就能收到。其实要吸收广播还:涉及权限、历程优先级、flag标签等各类无法吸收到广播的环境。总而言之静态广播注册是在包安装剖析的时间就开始注册,并将广播信息存储在PMS(PackageManagerService)中了。
    广播的发送紧张有几种:平凡广播、有序广播。
    前面都一样都是通过ContextImpl去与AMS打交道,然后AMS这边方法中会根据intent-filter查找出匹配的广播吸收者并颠末一系列的条件过滤. 终极会将满意条件的广播吸收者添加到BroadcastQueue中, 接着BroadcastQueue就会将广播发送给相应广播吸收者。应用吸收到广播, 同时onReceive()方法是在广播吸收者的主线程中被调用的。
增补小知识
1:全部静态广播Receiver 都是串行处理处罚,(静态广播吸收者属于在发送此广播时属于有序广播范畴)
2:动态广播 Receiver按照发送此广播时指定的方式 举行 串行大概并行分发
此中:假如是平凡广播:那么通过 并行方式分发
         假如是 有序广播(sendOrderxxxx):那么通过 串行方式分发
3:Android体系在处理处罚广播时:动态广播吸收者 优先于 静态广播吸收者 收到
4:广播分发处理处罚关键类:BroadcastQueue/ BroadcastRecord
5.当地广播:为相识决全局广播的安全性标题,Android引进了当地广播机制。当地广播发出后只可以大概在应用步调内部转达,也只有应用步调内部的吸收器能吸收到当地广播,这样广播的安全性标题就能得到解决了。当地广播和全局广播差异的地方在于当地广播紧张利用LocalBroadcastManager对广播的发送、注册、注销举行管理。
四、ContentProvider的启动过程


    ContentProvider的启动过程和其他3大组件根本雷同,都是通过AMS实现历程间的数据共享。
    在activity中假如想通过provider来实现增删查改,起首须要获取contentprovider,大抵过程为在context中获取contentResolver,然后通过contentResolver去ActivityManagerService中查询对应的provider,假如没有则进入PackageManagerService中查找:
    1)起首每个context类都会内部包罗了一个ContentResolver的子对象ApplicationContentResolver。
    2)通过调用ApplicationContentResolver的紧张方法query来获取CP的数据库数据。
    3)调用的过程起首会调用ContentResolver的核心方法acquireProvider()。而acquireProvider()方法是一个抽象方法,其实现是交由子类实现。
    4)通过子类的acquireProvider()方法实现相识到紧张的实现是交由ActivityThread类来完成。
    5)ActivityThread类会做出一个判断,假如当地生存一个须要获取的CP对象实例,就会直接返回这个对象实例,假如没有生存,则会访问AMS对象去查找获取一个对象的CP对象实例,当找到这个对象实例后会生存到当地以便日后快速获取。
    6)假如在AMS内里没有找到,就会继承深入到PMS里去从全部的provider中查找。
    7)获取到CP对象实例后会通过层层返回,末了再调用该CP对象的query方法获取相应的数据。
起首在应用的的manifest中须要举行读写权限说明,这个说明的界说跟之前provider界说中读写所需权限属性值是一样的:
    在activity中获取ContentResolver调用此中的操作方法时,须要传入相对应的参数:
    contentResolver.query(Uri uri, String[] projection,String selection, String[] selectionArgs,String orderBy);
    uri:传入对应uri是为了查找到对应的provider,跟provider在manifest中界说的authorities值是一样
    projection:选择须要返回的对象属性值,偶尔间不须要将对象的值全部返回。
    selection/selectionArgs:查询条件
    orderBy: 返回的对象排序方式
    雷同其他的delete、insert和update操作。最紧张的是传入准确的Uri才华找到对应的provider。
    此处加个小知识点:ContentProvider onCreate()优先实行于 Application onCreate()方法,感爱好的小同伴可以通过检察源码的方式验证。
浅谈一个小知识点—AMS的启动:

    AMS,即ActivityManagerService,是安卓java framework的一个服务,运行在system_server历程。
    在体系开机启动之后,system_server会实行三大服务启动
    startBootstrapServices() :启动引导服务,在这里实际上已经new了AMS,在new方法里,已经初始化了AMS的大部分紧张的属性。AMS的Looper和各种handler也是在这里准备好的。
    startCoreServices():核心服务。
    在创建完AMS之后,system_server的run方法会实行到startOtherServices(),在启动“其他服务”完毕之后,会调入到AMS的systemReady()方法,在这里会启动launcher。
    可以说,在这个方法实行完毕之后,体系就已经启动完成了。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2025-2-23 06:52, Processed in 0.171033 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表