…
…
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 sThreadInstance =
new ThreadLocal() {
@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
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 that 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 "
}
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);
…
…
//处理绘制流程
performDraw();
}
//下面我们开始分析Choreographer postCallback流程
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
//这里小小的说明一下这里记录的是开机到现在的时间
//不受设置时间的影响
//如果要计算时间间隔最好用 SystemClock.uptimeMillis()
final long now = SystemClock.uptimeMillis();
在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了
很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021最新上万页的大厂面试真题
七大模块学习资料:如NDK模块开发、Android框架体系架构…
只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021最新上万页的大厂面试真题
[外链图片转存中…(img-4S08yINo-1646218745071)]
七大模块学习资料:如NDK模块开发、Android框架体系架构…
[外链图片转存中…(img-MMcod8Qi-1646218745073)]
只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!