当前位置:   article > 正文

2024年安卓最新面试 100% 完全掌握:重新认识 View 的绘制流程(1),字节跳动面试官级别_view的绘制流程

view的绘制流程

写在最后

本次我的分享也接近尾声了,感谢你们在百忙中花上一下午来这里聆听我的宣讲,希望在接下来的日子,我们共同成长,一起进步!!!

最后放上一个大概的Android学习方向及思路(详细的内容太多了~),提供给大家:

对于程序员来说,要学习的知识内容、技术有太多太多,这里就先放上一部分,其他的内容有机会在后面的文章向大家呈现出来,不过我自己所有的学习资料都整理成了一个文档,一直在不断学习,希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!

Android架构师之路很漫长,一起共勉吧!

如果你觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

本文分为以下流程学习,阅读完本文将会学习到PhoneWindow,WindowManger,ViewRootImpl,View 等关键类的联系和作用。对window窗体机制以及绘制流程有所了解。

  1. 流程图分析

  2. 了解view绘制流程

  3. 了解setContentView如何附加到内容到页面

关键类解释

=====

  • Choreographer:协调动画、输入和绘图的时间。Choreographer从显示子系统接收定时脉冲(例如垂直同步),然后安排工作发生,作为渲染下一个显示帧的一部分。

一. 流程图分析

========

1.1 创建Activity到setContentView的窗口附加流程图


下图展示了window的创建到setContentView之后的窗体view树变化情况

activity 设置布局流程

1.2 view绘制流程图


绘制流程图

二. view绘制流程

===========

2.1 绘制流程分析


在我们调用requestLayout 和 invalidate的时候,我们会让view刷新布局和绘制。所以从这两个方法入手,可以完整地走一遍绘制流程。 绘制动画等行为主要通过Choreographer 类协调。

  1. 调用requestLayout 和 invalidate标记绘制和充布局信息

  2. Choreographer接受系统垂直同步等脉冲消息,在scheduleTraversals方法中回调执行doTraversal 开始遍历view树。

  3. 触发ViewRootImpl#performTraversals完成view树遍历

  4. 如果layoutRequested 为true,measureHierarchy 中测量 mView 及其子view

  5. 需要的话,触发ViewRootImpl#performLayout 完成布局

  6. 如果view没有隐藏且TreeObserver中没有拦截绘制,就调用performDraw,完成绘制

  7. 计算dirty脏区域

  8. 从mSurface中 获取脏区域的canvas,交给view绘制

2.2 ViewRootImpl 创建时机


从上面可以看到,所有的绘制和布局都是由ViewRootImpl#doTraversal触发,然后对其持有的view树进行遍历绘制。所以一定要了解ViewRootImpl和其持有的DecorView的创建和关联时机。关键流程如下:

  1. Activity#handleResume 的时候,调用WIndowManager#addView添加decorView

  2. 调用到WindowManagerGlobal#addView 的时候创建ViewRootImpl实例。

  3. 调用ViewRootImpl#setView完成一系列初始化方法

  4. 注册mDisplayListener 到DisplayManager,接收显示更新回调

  5. 调用 requestLayout 更新一次布局大小和位置信,以确保从系统接收任何其他事件之前进行过一次布局

  6. 通过WindowSession 调用addToDisplayAsUser,添加window

  7. 在接收系统事件的时候,调用scheduleTraversals 绘制view树

WindowMangerGlobal 最终调用的其实都是ViewRootImpl方法。ViewRootImpl在addView关联号DecorView后,还调用了setView方法进行初始化,接收垂直同步脉冲信息,代码如下:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,

int userId) {

mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);

// 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.

requestLayout();

try{

res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,

getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,

mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,

mAttachInfo.mDisplayCutout, inputChannel,

}

}

在初始化的最后,通过WindowSession 调用addToDisplayAsUser添加了window到屏幕显示中。

三. 附加contentView到界面

===================

当我们启动activity,将我们写的xml布局文件显示在屏幕上,其中经历了那些过程呢?我们要在界面上展示内容,有如下几个步骤:

  1. 启动activity,在performLaunchActivity的时候创建Activity并且attach和调用onCreate方法

  2. 在attach的时候,创建PhoneWindow实例并持有mWindow引用

  3. 调用setContentView 以附加内容到windows中

  4. 通过确认decorView 以及 subDecorView存在,创建DecorViewsubDecorView

  5. 添加ContentViewdecorView树中的 R.id.content节点

  6. handleResumeActivity的时候,调用WindowManager.addView。关联ViewViewRootImpl,后续便可以绘制。

3.1 创建PhoneWindow


我们先看启动activity的方法,ActivityThread#performLaunchAcivity。 从该方法源码中可知,启动activity的方法流程如下:

  1. 创建Activity实例 ,在Instrumentation#newActivity完成

  2. 创建PhoneWindows附加到Activity。在Activity#attachAcitivity完成

  3. 调用Activity的onCreate生命周期,代码是Instrumentation#callActivityOnCreate

  4. onCreate中执行用户自定义的代码,比如setContentView

所以可知,在activity准备启动的时候,就已经完成了PhoneWindows实例的创建。而接下来就执行到了我们在Activity#onCreate中调用setContentView方法设置的自定义布局。

3.2 setContentView的本质


activity在启动之后,我们通常在onCreate调用setContentView中设置自己的布局文件。我们来具体看看setContentView做了什么。 setContentView方法本质其实是向android.R.id.content添加自己。 我们看AppCompatDelegateImpl#setContentView

@Override

public void setContentView(View v, ViewGroup.LayoutParams lp) {

///确认好 window decorView 以及 subDecorView

ensureSubDecor();

//向 android.R.id.content 添contentView

ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);

contentParent.removeAllViews();

contentParent.addView(v, lp);

mAppCompatWindowCallback.getWrapped().onContentChanged();

}

这一块代码关键在于向id为android.R.id.content的子view中添加contentView。 addView的过程自然会触发布局的重新渲染。 关键之处还是在于ensureSubDecor()方法中对于decoView 以及subDecorView的实例化创建工作。

3.3 确认window ,decorView 以及 subDecorView


先看看AppCompatDelegateImpl#ensureSubDecor()的主要实现:

private void ensureSubDecor() {

if (!mSubDecorInstalled) {

mSubDecor = createSubDecor();

}

}

private ViewGroup createSubDecor() {

// Now let’s make sure that the Window has installed its decor by retrieving it

ensureWindow();

mWindow.getDecorView();

final LayoutInflater inflater = LayoutInflater.from(mContext);

ViewGroup subDecor = null;

//省略其他样式subDecor布局的实例化

//包含 actionBar floatTitle ActionMode等样式

subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);

//省略状态栏适配代码

//省略actionBar布局替换代码

mWindow.setContentView(subDecor);

return subDecor;

}

代码很长,上面是经过省略之后的主要代码。可以看到代码逻辑很清晰:

  • 步骤一:确认window并attach(设置背景等操作)

  • 步骤二:获取DecorView,因为是第一次调用所以会installDecor(创建DecorView和Window#ContentLyout)

  • 步骤三:从xml中实例化出subDecor布局

  • 步骤四:设置内容布局: mWindow.setContentView(subDecor);

3.4 初始化 installDecor


关键两处代码是Window#installDecor 和 Window#setContentView。 先看一下Window#installDecor的代码:

private void installDecor() {

mForceDecorInstall = false;

mDecor = generateDecor(-1);

if (mContentParent == null) {

//R.id.content

mContentParent = generateLayout(mDecor);

尾声

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

  • 思维脑图
  • 性能优化学习笔记


  • 性能优化视频

    当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

mg-Dx0xnGzw-1715832991472)]
[外链图片转存中…(img-434vQFMx-1715832991472)]

  • 性能优化视频
    [外链图片转存中…(img-r6qe4K1V-1715832991473)]
    当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/738033
推荐阅读
相关标签
  

闽ICP备14008679号