一、概述
本文将从startActivity开始讲解Android屏幕刷新机制,前面的文章有分析过startActivity的启动过程,这里将重点分析WMS相关的过程,从而了解Android屏幕刷新机制原理。前面介绍的startActivity启动过程的流程图如下:
二、View的绘制过程
从启动过程中的performLaunchActivity开始分析,View真正的绘制是在Activity中的onResume方法中。
2.1 AT.performLaunchActivity
[->ActivityThread.java]
1 | private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { |
2.2 Activity.attach
[->Activity.java]
1 | final void attach(Context context, ActivityThread aThread, |
这里比较重要的操作是创建PhoneWindow,PhoneWindow是window唯一的实现类。每一个Activity都有一个PhoneWindow对象,PhoneWindow对象中有一个DecorView实例,通过这个实例来进行View相关的操作。
2.3 Activity.setContentView
[->Activity.java]
onCreate方法里面有一个setContentView
1 | public void setContentView(@LayoutRes int layoutResID) { |
mWindow为上面创建的PhoneWindow对象,其类结构如下图所示
[->PhoneWindow.java]
1 | public void setContentView(int layoutResID) { |
2.3.1 installDecor
[->PhoneWindow.java]
1 | private void installDecor() { |
2.3.2 DecorView创建
1 | protected DecorView generateDecor(int featureId) { |
DecorView继承于FrameLayout,通过setContentView将Activity中的布局view添加DecorView中
2.3.3 generateLayout
1 | protected ViewGroup generateLayout(DecorView decor) { |
contentParent通过findviewById(com.android.internal.R.id.content)得到,后面通过mLayoutInflater.inflate(layoutResID, mContentParent)加载setContentView中的布局文件。
2.4 AT.handleResumeActivity
[->ActivityThread.java]
1 | public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, |
2.5 Activity.makeVisible
[->Activity.java]
1 | void makeVisible() { |
在 Activity.attach方法中进行的初始化
1 | mWindow = new PhoneWindow(this, window, activityConfigCallback); |
mWindowManager 在Window中初始化
1 | mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); |
2.6 WMI.addView
[->WindowManagerImpl.java]
1 | private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); |
2.7 WMG.addView
[->WindowManagerGlobal.java]
1 | public void addView(View view, ViewGroup.LayoutParams params, |
WindowManagerGlobal是WindowManagerImpl中的成员变量,其和ViewRootImpl,WindowSession关系图如下,WindowManager和WindowManagerService是通过Session进行通信的。具体可参考WMS启动分析
2.8 VRI.setView
[->ViewRootImpl.java]
1 | public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { |
2.9 VRI.requestLayout
[->ViewRootImpl.java]
1 | @Override |
2.9.1 VRI.scheduleTraversals
[->ViewRootImpl.java]
1 | void scheduleTraversals() { |
mTraversalRunnable实现如下:
1 | final class TraversalRunnable implements Runnable { |
这里向Choreographer发送一个Runnable消息,Choreographer主要作用是获取Vsync同步信号并控制应用主线程完成图像绘制的类。
2.9.2 Choreographer.postCallback
[->Choreographer.java]
1 | public void postCallback(int callbackType, Runnable action, Object token) { |
最后延迟和非延迟都会执行到scheduleFrameLocked方法
2.9.2.1 scheduleFrameLocked
[->Choreographer.java]
1 | private void scheduleFrameLocked(long now) { |
USE_VSYNC默认是true,当前线程和Choreographer绑定的线程一致,调用scheduleVsyncLocked,否则通过mHandler发送消息,在Choreographer线程中处理。这两个分支最后都会执行scheduleVsyncLocked方法。
2.9.2.2 scheduleVsyncLocked
[->Choreographer.java]
1 | private void scheduleVsyncLocked() { |
2.9.2.3 scheduleVsync
[->DisplayEventReceiver.java]
1 | public void scheduleVsync() { |
这里调用到了native方法,这里主要是向底层注册Vsync信号,当底层有Vsync信号来时,会调用onVsync方法。后面文章会详细介绍Choreographer这里相关的操作。
2.9.2.4 FrameDisplayEventReceiver
[->FrameDisplayEventReceiver.java]
1 | private final class FrameDisplayEventReceiver extends DisplayEventReceiver |
发送异步消息,最后会执行doFrame方法
2.9.2.5 doFrame
[->Choreographer.java]
1 | void doFrame(long frameTimeNanos, int frame) { |
这里主要是执行队列里面的任务,例如之前添加的mTraversalRunnable。
2.9.2.6 doCallbacks
[->Choreographer.java]
1 | void doCallbacks(int callbackType, long frameTimeNanos) { |
2.9.3 VRI.doTraversal
[->ViewRootImpl.java]
1 | void doTraversal() { |
2.9.4 VRI.performTraversals
[->ViewRootImpl.java]
1 | private void performTraversals() { |
这里主要是判断是否需要执行performMeasure() ,performLayout(),performDraw()这三个过程都会遍历View树刷新需要更新的view。
2.10 Session.addToDisplay
[->Session.java]
1 | @Override |
2.11 WMS.addWindow
[->WindowManagerService.java]
1 | public int addWindow(Session session, IWindow client, int seq, |
2.11.1 WindowState
[->WindowState.java]
1 | WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, |
2.11.2 ws.attach
[->WindowState.java]
1 | void attach() { |
[->Session.java]
1 | void windowAddedLocked(String packageName) { |
2.11.3 创建SurfaceSession
[->SurfaceSession.java]
1 | public SurfaceSession() { |
[->core/jni/android_view_SurfaceSession.cpp]
1 | static jlong nativeCreate(JNIEnv* env, jclass clazz) { |
创建SurfaceComposerClient,作为SurfaceFlinger通信的对象
2.12 WMS.updateFocusedWindowLocked
[->WindowManagerService.java]
1 | boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { |
三、总结
本文详细分析了Android屏幕刷新机制中的View的绘制过程,这里只介绍到framework层。
1.从Activity的启动流程开始分析,在performLaunchActivity方法中调用Activity.attach方法创建PhoneWindow;
2.PhoneWindow中有一个DecorView实例,DecorView继承于FrameLayout,通过setContentView将Activity中的布局view添加DecorView中;
3.调用handleResumeActivity,进入到Activity的onResume方法,后面再调用Activity.makeVisible方法;
4.makeVisible方法调用了WindowManagerGlobal.addView方法,创建了ViewRootImpl对象;
5.调用ViewRootImlp中的requestLayout,再调用到里面的scheduleTraversals进行绘制;
6.scheduleTraversals方法,向主线程发送同步屏障消息,通过mChoreographer.postCallback将mTraversalRunnable放到mCallbackQueues队列里面,在同一个帧内,多次请求requestLayout,只会调用一次scheduleTraversals。
7.如果当前线程是主线程则调用nativeScheduleVsync,如果不是则通过handler发送到主线程进行处理;
8.native方法主要是向底层注册监听Vsync屏幕刷新信号,当下一个Vsync信号发出时,底层会回调onVsync方法
9.onVsync方法,会向主线程发送Runnable异步消息,里面会执行doFrame方法;
10.doFrame会执行mCallbackQueues队列里面的任务,取出来的任务会执行doTraversal方法
11.doTraversal方法会先移除主线程中同步屏障,然后调用performTraversals,根据当前的状态判断是否需要执行performMeasure,performLayout,performDraw,这三个过程都会遍历View树刷新需要更新的view。
12.通过Session.addToDisplay向WMS添加Window,WMS建立SurfaceComposerClient,然后会在SurfaceFlinger创建Client与之对应,后面通过ISurfaceComposerClient和SurfaceFlinger进行通信。