一、AMS服务启动
this = SysteServer
this.main -> run //The main entry point from zygote.
this.startBootstrapServices -> ActivityManagerService.Lifecycle
二、WMS与App的交互
Activity启动流程https://my.oschina.net/u/3336230/blog/1522704
从AMS-> startActivity 开始,一路略过Activity启动过程直达
ActivityThread.handleResumeActivity:
->decor.setVisibility(View.INVISIBLE);
wm.addView(decor, l); //wm 是WindowManagerImpl
->WindowManagerImpl.addView // WindowManagerGlobal.的代理
->WindowManagerGlobal.addView
->ViewRootImpl.setView // 获得WMS.WindowSession,APP与WMS跨进程通信通过IWindowSession
// IWindow.Stub用来WMS与APP(ViewRootImpl)通信
->ViewRootImpl.requestLayout
->ViewRootImpl.mTraversalRunnable
->ViewRootImpl.performTraversals // 开启真正的绘制,待细研究
->ViewRootImpl.performMeasure // Ask host how big it wants to be
->mView.measure //DecorView ,传入的childWidthMeasureSpec,childHeightMeasureSpec为窗口的大小和mode
//这里要说明的是对于ViewGroup的子类需要重写onMeasure方法,需要先(measureChildWithMargins)测
//量其子类的最大宽高+padding,然后结合自身大小限制计算出合适的mMeasureSpec
//View的子类重写onMeasure只需给出自己的大小和内容(背景图片,字体大小)比较后合适的值
->mView.layout
->mView.draw
三、MotionEvent传递、分发
Android事件这块分两部分:事件来源(InputReader从底层读取)、事件分发(在页面各View的传递)
MotoinEvent 是java层封装的数据结构,它的源数据结构是由InputReader从文件读取而来。
InputDispatcher线程负责分发事件到UI,这两个线程都是从InputManagerService初始化InputManager->start 时启动的
1、事件从底层分发到ActivityThread通过Handler,然后通过ViewRootImpl一路到
DecorView.dispatchTouchEvent.callback->Activity->
PhoneWindow.superDispatchTouchEvent->
DecorView.superDispatchTouchEvent->
ViewGroup.dispatchTouchEvent
java.lang.Throwable: stack dump
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at java.lang.Thread.dumpStack(Thread.java:496)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at com.jym.floatwinplugin.view.widget.FloatBallView.dispatchTouchEvent(FloatBallView.java:250)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.View.dispatchPointerEvent(View.java:7426)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3220)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3165)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4292)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4271)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4363)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.os.MessageQueue.nativePollOnce(Native Method)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.os.MessageQueue.next(MessageQueue.java:125)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.os.Looper.loop(Looper.java:124)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5041)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at java.lang.reflect.Method.invoke(Method.java:511)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
05-09 11:58:50.623 11447-11447/com.float.mall W/System.err: at dalvik.system.NativeStart.main(Native Method)
四、性能优化总结
1、界面绘制常识
UI在1s内显示60帧,那么这种比较细腻的界面显示不会感觉到卡顿。这就要求每帧画面需要在16ms内完成绘制。24 Fps 是人眼能感知的连续线性的运动,所以是电影胶圈的常用帧率。
影响绘制的因素:
垃圾回收是影响绘制的罪魁祸首之一,好消息是Android4.4 引进了新的 ART 虚拟机来取代 Dalvik 虚拟机,极大的提高了GC的回收效率,通常在2~3ms
UI线程是主线程,主线程大量的耗时操作会直接影响UI渲染,不过在 Android 5.0 版本里,Android 框架层引入了 “ Render Thread ” ,用于向 GPU 发送实际渲染的操作。这个线程减轻了一些 UI 线程减少的操作。但是输入、滚动和动画仍然在 UI thread,因为 Thread 必须能够响应操作。
2、性能优化工具
Hierarchy View 布局层次管理器,可以有效的分析复杂布局结构
Lint 给XML布局和代码不合理处提示
- 包含无用的分支,建议去除;
- 包含无用的父控件,建议去除;
- 警告该布局深度过深;
- 建议使用 compound drawables ;
- 建议使用
merge
标签;
Systrace 可以直观看到流程执行耗时的地方,但使用麻烦
Track 可以直观的跟踪到每个函数的耗时
OverDraw APP开发者选项中开启,过度绘制的UI会显示不同颜色
- 没颜色:没有过度绘制,即一个像素点绘制了 1 次,显示应用本来的颜色;
- 蓝色:1倍过度绘制,即一个像素点绘制了 2 次;
- 绿色:2倍过度绘制,即一个像素点绘制了 3 次;
- 浅红色:3倍过度绘制,即一个像素点绘制了 4 次;
- 深红色:4倍过度绘制及以上,即一个像素点绘制了 5 次及以上;
原因是视图相互重叠和每个View都有相同背景
StirctMode 严格模式,检查主线程有耗时操作会在手机闪烁红框
3、不合理的XML布局
由于UI显示出来是在解析、测量布局之后才开始显示,所以布局层次太深会导致时间变长
4、优化建议
- 避免复杂的view层级,寻找最优方案布局
- 避免使用RelativeLayout,它是个耗时的布局,需要测量两次,随着嵌套越多,性能会越差。确实需要可以用GridLayout代替
- 不要使用绝对布局
AbsoluteLayout
- 使用
</include>
标签重用可复用的布局 - 使用merge标签
- 尽量避免使用layoutweight,使用它的linearLayout会绘制子组件两次
- ViewStub懒加载不常用布局
- 主线程不要做耗时操作
五、Binder
Binder也不是Android自己开发的,它的前身是OpenBinder。
Binder模型包含四部分,client、server、serverManager、binder驱动,其中真正实现IPC通信的是binder驱动部分。
传统的linux进程通信方式有管道、socket、system V IPC等。
IPC | 数据拷贝次数 |
共享内存 | 0 |
Binder | 1 |
Socket/管道/消息队列 | 2 |
binder只发生一次拷贝的奥秘在于binder驱动的实现,它实现了mmap(物理存储介质的文件系统)的调用。在/dev/binder文件,采用mmap开辟一块缓冲区,并且这块内存会映射到用户空间和内核空间,并且统一由binder驱动管理。
六、Android绘制过程
ViewRootImpl
//绘制过程一言以蔽之,即Acitivty的顶层View是DecorView,setContentView把view放到了DecorView的id为content的子
//view里,Activity中有个PhoneWindow,和WindowManagerImpl(实际上是WindowManagerGlobal的代理)。
//在ActivityThread的handleResumeAcitivity方法中
//WindowManagerImpl.add DecorView
//WindowManagerGlobal.add DecorView
//ViewRootImpl.mView = DecorView
//ViewRootImpl在performTraversals通过Surface locak一块Raw buffer为Canvas传给decorView的draw方法
public final class ViewRootImpl implements ViewParent{
final IWindowSession mWindowSession;
final W mWindow; // 通过调用mWindowSession传给WMS
View mView; // DecorView
Surface mSurface = new Surface();// 操作一块Raw buffer(内存或显存),被SurfaceFlinger管理抛到屏幕
private boolean draw(...){
drawSoftware();
}
private boolean drawSoftware(...){
canvas = mSurface.lockCanvas(dirty);
mView.draw(canvas);
}
}
Surface
// Surface使用的不是java层new 的这个无参Surface,而是使用的wms中new的一个参数为SurfaceSession的Surface
// 之后图像数据会以FrameBuffer和pageflipping的方式一帧一帧经过SurfaceFlinger混合后显示出来
七、常用第三方框架
1、网络框架
okhttp、retrofit出自Square公司
2、异步处理
Rxjava、EventBus
3、图片加载
Glide、Picasso出自Square
4、性能优化
Leakcanary
Blockcanary