Zygote的启动过程
1.系统启动init进程时会启动Zygote进程(负责Android运行时进程和应用进程的启动)
2.Zygote进程会首先启动SystemServer进程,SystemServer进程会启动系统的关键服务(PMS和AMS)
3.当启动应用程序时,AMS通过socket向Zygote通知创建新的进程
Android应用程序安装过程
SystemServer进程启动PackageManagerService服务实例,添加到ServiceManager(负责管理系统中的Binder对象)
PackageManagerService.main()扫描指定目录的apk归档文件
/system/framework
/system/app
/vendor/app
/data/app
/data/app-private
- 对apk文件解析AndroidManifest.xml各个标签,得到的package、provider、service、receiver和activity等信息保存在PackageManagerService服务的内存中。
- 下载安装过程下载apk->拷贝到指定目录->解析apk归档文件的AndroidManifest.xml的应用程序的信息到packageManagerServices中#应用程序启动流程
- Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity;
- ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
- Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;
- ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
- AMS通知ActivityThread对象中调用bindApplication()方法. 送到消息队列中, 最终通过handleBindApplication()方法处理该消息. 然后调用makeApplication()方法来加载Application的classes到内存中,然后通知AMS。
- ActivityManagerService通过Binder进程间通信机制通知ActivityThread,可以真正执行Activity的启动。
Launcher启动过程
- SystemServer进程启动ActivityManagerService服务实例,添加到ServiceManager(负责管理系统中的Binder对象)
- ActivityManagerService向PackageManagerService查询Category类型为HOME的Activity,通过 ActivityStack.startActivityLocked将Launcher启动起来
- Launcher在onCreate()中,通过这个PackageManagerService.queryIntentActivities接口来取回所有Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity。显示这些到页面上。
Activity启动流程
- AMS创建新进程,创建ActivityThread实例,将ApplicationThread的Binder对象传递给AMS并且开始了消息循环。
- 从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;
- 从ActivityManagerService进程又回到新进程中,最终将服务启动起来。
3.1. performLaunchActivity()初始化Activity
3.1.1 classLoader加载Activity类,mInstrumentation.newActivity实例化Activity
3.1.2 makeApplication如果进程中没有就重新创建
3.1.3 Activity.attach()将上下文信息设置到Activity中 包括window创建
3.1.4 mInstrumentation.callActivityOnCreate->onCreate()
调用setContentView为decorView设置页面内容
3.1.5 Instrumentation.callActivityOnStart->onStart()
初始化应用数据准备
3.2 handleResumeActivity激活Activity
3.2.1 mInstrumentation.callActivityOnResume->onResume()
做准备显示到交互的处理
3.2.2 wm.addView添加window的decorView开始绘制显示页面交互
Service启动流程
service将计算型的逻辑单独放在一个进程内执行提高用户体验。
start流程
- AMS创建新进程(会判断ProcessRecord不存在才去创建),创建ActivityThread实例,将ApplicationThread的Binder对象传递给AMS并且开始了消息循环。
- 从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;
- 从ActivityManagerService进程又回到新进程中,最终将服务启动起来。
3.1 handleCreateService()初始化Service
3.1.1 通过ClassLoader加载service类,然后的newInstance实例化Service
3.1.2 makeApplication如果进程中没有就重新创建
3.1.3 service.attach() 上下文信息设置到service中
3.1.4 service.onCreate()
回调 - 然后还会回新进程ApplicationThread.scheduleServiceArgs在主线程中回调
onStartCommand
bind流程
- MainActivity调用bindService函数通知ActivityManagerService,它要启动CounterService这个服务,ActivityManagerService于是在MainActivity所在的进程内部把CounterService启动起来,并且调用它的
onCreate
函数; - ActivityManagerService把CounterService启动起来后,继续调用CounterService的
onBind
函数,要求CounterService返回一个Binder对象给它; - ActivityManagerService从CounterService处得到这个Binder对象后,就把它传给MainActivity,即把这个Binder对象作为参数传递给MainActivity内部定义的ServiceConnection对象的onServiceConnected函数;
- MainActivity内部定义的ServiceConnection对象的onServiceConnected函数在得到这个Binder对象后,就通过它的getService成同函数获得CounterService接口。
PhoneWindow流程
- 在Activity的attach中创建PhoneWindow并完成相关设置
1.1 调用PolicyManager.makeNewWindow创建PhoneWindow,
1.2 设置window的Calback将IO输入事件分发给Activity(softMode设置)
1.3 设置windowManager,mAppToken为ActivityManagerService侧ActivityRecord(Binder对象),mAppName为Activity组件名称
- 在onCreate中的setContentView(rId)完成window的视图内容的设置
2.1 installDecor()根据Theme和Feature完成window的顶级视图mDecor以及找到mContentParent
2.2 通过mLayoutInflater.inflate(layoutResID, mContentParent)设置到mContentParent中
- 在handleResumeActivity()中wm.addView()将window的内容绘制出来
3.1 WindowManagerImpl.addView将decorView、viewRoot、LayoutParamas分别添加到mViews[i]、mRoots[i]和mParams[I]中
3.2 viewRootImpl.setView()完成相关成员的配置工作和绘制
3.2.1 将decorView设置到mAttachInfo.mRootView上
3.2.2 panelParentView不为空表示window是子窗口,需要保存ApplicationWindowToken到mAttachInfo中
3.2.3 调用requestLayout()执行view树的绘制流程
View绘制流程
- viewRootImpl的requestLayout()和invalidateChildInParent()最终都调用performTraversals()开始执行测量、布局、绘制
- mView.measure测量所有view的宽高这里就比按照流程叙述了,按照我自己的通俗的理解来讲
前言:view测量时有限制MeasureSpec。自己的申请(layout_)告诉父亲,父亲根据自己的情况计算家里的情况给出的钱(空间)的使用限制。Mode:家里的情况,Size:到手钱自己当爸爸了 viewGroup(详情getChildMeasureSpec)
家里的情况 Mode,拿到手上有 size大小的钱
1.不管家里任何情况,只要儿子申请花调固定的数字childDimension>=0,超过限制也给,
儿子的Mode=EXACTLY,Size=childDimension
2.其他的话看家里情况
都用掉 EXACTLY:
儿子申请都给我吧 MATCH_PARENT:目标明确,给。儿子的Mode=EXACTLY,Size=size
儿子申请我自己算 WRAP_CONTENT:儿子的Model=AT_MOST,Size=size
家里手头紧不能超过 AT_MOST:
不管儿子申请 MATCH_PARENT 还是 WRAP_CONTENT:告诉子孙们手头紧Mode=AT_MOST,Size=size
不知道啥情况,但是手动有钱 UNSPECIFIED:
不管儿子申请 MATCH_PARENT 还是 WRAP_CONTENT:告诉子孙们家里不知道啥情况Mode=UNSPECIFIED,Size=size
自己绝育了View,祖宗传下来过日子之法 (详情resolveSize)
看家里情况
要你都用掉 EXACTLY:
都用光
家里手头紧不能超过 AT_MOST:
自己用多少算多少吧,不超过就行
不知道啥情况,但是手动有钱 UNSPECIFIED:
没限制,自己用多少算多少
- mView.layout 递归View树 根据viewGroup的layout规则设置所有子View的位置
3.1 ViewGroup必须重写onLayout,根据排列规则以及measure测量的宽高调用child.layout对子View进行设置
3.2 View的layout中调用setFrame完成对mLeft、mTop、mRight和mBottom赋值
总结:所有的View都得靠父布局通过自己的margin等相对规则确定位置 - mView.draw 递归View树绘制所有view到canvas上
4.1 draw()控制整体绘制流程,可被重写
4.2 drawBackground()绘制背景,不可被重写
4.3 ondraw()绘制主体,可被重写
4.4 dispatchDraw() 主要给ViewGroup重写分配给子View绘制,可重写
4.5 绘制滚动条和前景 在6.0合并到onDrawForeground(),可被重写
ps:其实还有一个draw被ViewGroup通过drawChild调用,这个draw拿到的canvas是完整的父View的canvas,应用view动画的矩阵之后在整个canvas里裁剪对应view位置和大小的一块canvas交给处理view自身绘制流程的draw方法
应用事件分发流程
通过View树传递触摸事件,一旦有View消费掉事件就不会继续向下传递,如果没有消费掉就会往上抛交给父View处理。down事件被View消费之后,后面连续的事件都会交给它处理。
- phoneWindow将事件回调Activity的dispatchTouchEvent()分发事件
- 如果Event是ACTION_DOWN的情况下会接着触发onUserInteraction方法。
- 分发给mContentParent的子View处理事件
- 若子view拦截了事件(返回true)则Activity.onTouchEvent方法就不会执行。
- dispatchTouchEvent 分发处理事件
- 通过disallowIntercept先判断子View是否不让ViewGroup拦截事件
- onInterceptTouchEvent()判断当前ViewGroup是否需要拦截该事件
- 不拦截就直接dispatchTransformedTouchEvent()分发给子View处理,如果子View没有处理就继续交给自己逻辑
- 拦截就交给自己处理,交给super.dispatchTochEvent()处理
- dispatchTouchEvent 分发处理事件
- 如果view可用则调用mOnTouchListener(可消费调触摸事件)
- 在onTochEvent中处理事件
3.1 如果view是disable且是cliable 则直接消费调事件
3.2 如果是enable且discliable直接返回 不消费事件
3.3 如果是enable且cliable则处理消费事件逻辑,如up事件就会触发clickListner
总结:view要消费调Down事件才会接受到后续事件,而事件达到view时可以被责任链里的ViewGroup拦截掉,一旦拦截掉后续的任何一个事件对View来说就不完整了,所以为了保证view可以获取所有事件,可以声明不让他们拦截自己的事件。自己也不要在onTouchListner里随便拦截会影响onTouchEvent的正常处理的。如果没有view处理就会向上继续传播处理
部分学习自老罗的博客