Activity 页面的绘制流程,移动端跨平台开发
//WindowManagerImpl 的 createLocalWindowManager 创建的是一个 WindowManagerImpl 对象
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
根据以上源码我们知道了注释 2 的 vm 其实就是 WindowManagerImpl 对象。注释 1 注释 2 这两个前菜已经给大家分析完了。下面我们进入主题 Activity 页面的绘制。
- (2)WindowManagerImpl.addView
通过前面的分析,我们可以知道注释 3 处其实就是调用了 WindowManagerImpl 的 addView 方法。下面我们来看看这个方法到底做了什么。
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//调用 WindowManagerGlobal 的 addView 方法
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
//WindowManagerGlobal 的 addView
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
......
ViewRootImpl root;
View panelParentView = null;
.....
.....
1.创建 ViewRootImpl 对象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
2.调用 ViewRootImpl 的 setView 方法
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
注释 1 是个很重要的点,这里创建了一个 ViewRootImpl 对象。
我们来解析一下这个 ViewRootImpl 里面需要关注的几个点。
我们先看看 ViewRootImpl 的构方法:
public ViewRootImpl(Context context, Display display) {
//获取 Session 对象
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
//主线程
mThread = Thread.currentThread();
//创建 Choreographer 对象,这个对象很重要,可以把它理解为一个 Handler
//Android 16.6ms 刷新一次页面它启到了主要作用
//我们马上看看这个 Choreographer 是个什么
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
}
ViewRootImpl 的构造方法里面我们暂时值关注两件事
1.获取了 Session 对象这个对象是我们与 WindowManagerService 交互的桥梁。
2.创建了 Choreographer 对象。
我们现来看看这个 Choreographer 对象到底是什么,为什么它那么重要呢?
public static Choreographer getInstance() {
return sThreadInstance.get();
}
// Thread local storage for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
//注意了这里其实就是主线程的 Looper
//ViewRootImpl 对象就是在主线程创建的
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
//创建 Choreographer 对象
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
//前面我们说了正常情况瞎这个 looper 对象就是主线程的 looper 对象
//所以通过这个 Handler 发送的消息都是在主线程处理的
mHandler = new FrameHandler(looper);
//创建 FrameDisplayEventReceiver
//这个对象可以理解为一个任务
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//可以理解为绘制任务队列
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
// b/68769804: For low FPS experiments.
setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper) {
super(looper);
}
//这个的 onVsync 方法是什么时候调用的呢?
//我们知道 Android 没 16.6ms 都会刷新一次屏幕,原理其实就是这个 Vsync 导致的
//这个 Vsync 信号是从底层传递上来的
//onVsync 这个方法也是通过 jni 从底层调用上来,这个方法不会被 java 层调用
//每 16.6ms 调用一次
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
// Ignore vsync from secondary display.
// This can be problematic because the call to scheduleVsync() is a one-shot.
// We need to ensure t
hat we will still receive the vsync from the primary
// display which is the one we really care about. Ideally we should schedule
// vsync for a particular display.
// At this time Surface Flinger won't send us vsyncs for secondary displays
// but that could change in the future so let's log a message to help us remember
// that we need to fix this.
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
//通过 Handler 把自身作为一个任务发送到主线程的消息队列去做处理
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
//当绘制任务被处理时调用 doFrame 方法
doFrame(mTimestampNanos, mFrame);
}
}
void doFrame(long frameTimeNanos, int frame) {
.....
.....
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
"previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
//执行这一次队列中的绘制任务
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
......
......
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
final long now = System.nanoTime();
//根据 callbackType 取出 mCallbackQueues 的任务
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
synchronized (mLock) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
//for 循环执行需要绘制的任务
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
", action=" + c.action + ", token=" + c.token
", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);
}
}
}
上面我们简单的讲了 ViewRootImpl 的创建和 Choreographer 的创建。我们知道了每 16.6ms 底层都会通过 jni 调用成员变了 mDisplayEventReceiver 的 onVsync 方法,这个方法里会通过成员变量 mHandler(与主线程 Looper 绑定的 Handler),把自己作为一个任务发送到主线程去执行。
最后调用 doFrame()方法来处理 mCallbackQueues 队列中的绘制任务。我们可以猜测最后我们 Activity 页面的绘制任务也会被添加到这个 mCallbackQueues 队列中。
下面我们再来看最后也是最重要的一步。
- (3)ViewRootImpl.setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//1.请求布局绘制
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//2.通过构造方法里创建的 Session 对象向 WindowManangerService 请求将我们创建好的 Surface 对象添加到 屏幕上
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
}
}
}
}
由于今天我们讲绘制流程,我们就主要来看看注释 1 做了写什么事。我们按照方法的调用流程来看看源码。
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查是否是主线程要求更新 UI
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//调用 Choreographer 的 postCallback 方法
//mTraversalRunnable 就是一个处理绘制的任务
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
.....
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
......
......
performTraversals();
......
......
}
//performTraversals 最后会调用 performMeasure,performLayout,performDraw
//来处理界面的测量,布局和绘制流程
private void performTraversals() {
....
.....
//处理测量流程
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
.....
.....
//处理布局流程
performLayout(lp, mWidth, mHeight);
...
...
评论