View 自定义 - 绘制前的准备 DecorView

android fragment中引入自定义view_Android:一篇文章带你完全梳理自定义View工作流程... 前言自定义View 是 Android 开发者必须了解的基础网上有大量关于自定义View 原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化等等今天,我将全面总结自定义View 的原理,我能保证这是市面上的最全面、最清晰、最易懂的本文秉着“结论先行、详细分析在后”的原则,即先让大家感性认识,再通过理性分析从而理解问题; 所以,请各位读者先记住结论,再往下继续看分析; 文章... 阅读详情

一、概念

图中可以看出 ViewRoot 最后一步是绘制,在绘制之前系统会有一些准备,即前面几个步骤:创建PhoneWindow、DecorView、ViewRootmpl。

二、DecorView 的创建

DecorView的创建开始是从 Activity 中 setContentView() 开始的。

  • 创建抽象类 Window 的子类 PhoneWindow 实例。
  • 为 PhoneWindow 对象设置 WindowManager 对象。
  • 为 PhoneWindow 对象创建一个 DecroView 对象(根据所选的主题样式增加)。
  • 为 DecroView 对象中的 content 增加 Activity 中设置的布局文件。

此时,DecorView(即顶层View)已创建和添加Activity中设置的布局文件中,但目前仍未显示出来,即不可见。

/**
  * 具体使用:Activity的setContentView()
  */
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

/**
  * 源码分析:Activity的setContentView()
  */
   public void setContentView(int layoutResID) {
        // getWindow() 作用:获得Activity 的成员变量mWindow ->>分析1
        // Window类实例的setContentView() ->>分析2
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
   }

/**
  * 分析1:成员变量mWindow
  */
  // 1. 创建一个Window对象(即 PhoneWindow实例)
  // Window类 = 抽象类,其唯一实现类 = PhoneWindow
  mWindow = new PhoneWindow(this, window);
  
  // 2. 设置回调,向Activity分发点击或状态改变等事件
  mWindow.setWindowControllerCallback(this);
  mWindow.setCallback(this);

  // 3. 为Window实例对象设置WindowManager对象
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    }

/**
  * 分析2:Window类实例的setContentView()
  */
  public void setContentView(int layoutResID) {
        // 1. 若mContentParent为空,创建一个DecroView
        // mContentParent即为内容栏(content)对应的DecorView = FrameLayout子类
        if (mContentParent == null) {
            installDecor(); // ->>分析3
        } else {
            // 若不为空,则删除其中的View
            mContentParent.removeAllViews();
        }
        // 2. 为mContentParent添加子View
        // 即Activity中设置的布局文件
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();//回调通知,内容改变
        }
    }

/**
  * 分析3:installDecor()
  * 作用:创建一个DecroView
  */
  private void installDecor() {
    if (mDecor == null) {
        // 1. 生成DecorView ->>分析4
        mDecor = generateDecor(); 
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    // 2. 为DecorView设置布局格式 & 返回mContentParent ->>分析5
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor); 
        ...
        } 
    }
}

/**
  * 分析4:generateDecor()
  * 作用:生成DecorView
  */
  protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }
    // 回到分析原处

/**
  * 分析5:generateLayout(mDecor)
  * 作用:为DecorView设置布局格式
  */
  protected ViewGroup generateLayout(DecorView decor) {
        // 1. 从主题文件中获取样式信息
        TypedArray a = getWindowStyle();
        // 2. 根据主题样式,加载窗口布局
        int layoutResource;
        int features = getLocalFeatures();
        // 3. 加载layoutResource
        View in = mLayoutInflater.inflate(layoutResource, null);
        // 4. 往DecorView中添加子View
        // 即文章开头介绍DecorView时提到的布局格式,那只是一个例子,根据主题样式不同,加载不同的布局。
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 
        mContentRoot = (ViewGroup) in;
        // 5. 这里获取的是mContentParent = 即为内容栏(content)对应的DecorView = FrameLayout子类
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); 
        return contentParent;
    }

三、DecorView 的显示

在主线程创建时,会调用handleResumeActivity(),DecorView的显示操作从此处开始。

  • 将 DecorView 对象添加到 WindowManager 中。
  • 创建 ViewRootImpl 对象。
  • WindowManager 将 DecorView 对象交给 ViewRootImpl 对象。
  • ViewRootImpl 对象通过 Handler 向主线程发送了一条触发遍历操作的消息:performTraversals(),该方法用于执行 View 的绘制流程(measure、layout、draw)。 

ViewRootImpl 对象中接收的各种变化(如来自WmS的窗口属性变化、来自控件树的尺寸变化、重绘请求等都引发 performTraversals() 的调用及完成相关处理,并最终显示到可见的Activity中。

/**
  * 源码分析:主线程创建时,调用的handleResumeActivity()
  */
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
/**
  * 源码分析:Activity的setContentView()
  */
 final void handleResumeActivity(IBinder token,
    boolean clearHide, boolean isForward, boolean reallyResume) {
    ActivityClientRecord r = performResumeActivity(token, clearHide);
    if (r != null) {
        final Activity a = r.activity;
          if (r.window == null && !a.mFinished && willBeVisible) {
        // 1. 获取Window实例中的Decor对象
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        // 2. DecorView对用户不可见
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        // 3. DecorView被添加进WindowManager了
        // 此时,还是不可见
        if (a.mVisibleFromClient) {
            a.mWindowAdded = true;
            wm.addView(decor, l);
        }
        // 4. 此处设置DecorView对用户可见
        if (!r.activity.mFinished && willBeVisible
            && r.activity.mDecor != null && !r.hideForNow) {
             if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                    // —>>分析1
                }
            }
    }
/**
  * 分析1:Activity.makeVisible()
  */
  void makeVisible() {
   if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            // 1. 将DecorView添加到WindowManager ->>分析2
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        // 2. DecorView可见
        mDecor.setVisibility(View.VISIBLE);
    }

/**
  * 分析2:wm.addView
  * 作用:WindowManager = 1个接口,由WindowManagerImpl类实现
  */
  public final class WindowManagerImpl implements WindowManager {    
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow); ->>分析3
    }
}

/**
  * 分析3:WindowManagerGlobal 的addView()
  */
  public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {

     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
     ...
     synchronized (mLock) {
     // 1. 实例化一个ViewRootImpl对象
     ViewRootImpl root;
     root = new ViewRootImpl(view.getContext(), display);
     view.setLayoutParams(wparams);
     mViews.add(view);
     mRoots.add(root);
     mParams.add(wparams);
     }
     // 2. WindowManager将DecorView实例对象交给ViewRootImpl 绘制View
     root.setView(view, wparams, panelParentView);
     // ->> 分析4
       }
    }
 }

/**
  * 分析4:ViewRootImpl.setView()
  */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        requestLayout(); // ->>分析5
    }

/**
  * 分析5:ViewRootImpl.requestLayout()
  */
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            // 1. 检查是否在主线程
            checkThread();
            mLayoutRequested = true;//mLayoutRequested 是否measure和layout布局。
            // 2. ->>分析6
            scheduleTraversals();
        }
    }

/**
  * 分析6:ViewRootImpl.scheduleTraversals()
  */
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // 通过mHandler.post()发送一个runnable,在run()方法中去处理绘制流程
            // 与ActivityThread的Handler消息传递机制相似
            // ->>分析7
            mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }

/**
  * 分析7:Runnable类的子类对象mTraversalRunnable
  * 作用:在run()方法中去处理绘制流程
  */
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal(); // ->>分析8
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

/**
  * 分析8:doTraversal()
  */
    void doTraversal() {
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            performTraversals(); 
            // 最终会调用performTraversals(),从而开始View绘制的3大流程:Measure、Layout、Draw
    }

// 注:
// a. ViewRootImpl中W类是Binder的Native端,用于接收WmS处理操作
// b. 因W类的接收方法是在线程池中的,故可通过Handler将事件处理切换到主线程中

android 自定义 framelayout_Android:一篇文章带你完全梳理自定义View工作流程 前言自定义View 是 Android 开发者必须了解的基础网上有大量关于自定义View 原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化等等今天,我将全面总结自定义View 的原理,我能保证这是市面上的最全面、最清晰、最易懂的本文秉着“结论先行、详细分析在后”的原则,即先让大家感性认识,再通过理性分析从而理解问题; 所以,请各位读者先记住结论,再往下继续看分析; 文章... 阅读详情

相关推荐

Android:一篇文章带你完全梳理自定义View工作流程

前言 自定义View 是 Android 开发者必须了解的基础 网上有大量关于自定义View 原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化等等 今天,我将全面总结自定义View 的原理,我能保证这是市面上的最全面、最清晰、最易懂的 本文秉着“结论先行、详细分析在后”的原则,即先让大家感性认识,再通过理性分析从而理解问题; 所以,请各位读者先记住结论,再往下继续看分析; 文章较长,阅读需要较长时间,建议收藏等充足时间再进行阅读 目录 1. 储备知识 1.1 View

1 514

Android 活动、窗、DecorView、ViewRoot

Android 活动、窗、DecorView、ViewRoot

李青涛的博客 1959

基于stm32f407VGT6控制WS2812的TIM1+PWM+DMA实现方式

项目中使用到了ws2812灯带,作为产品的外观显示灯,经过开发之后,整理一下,仅供大家参考。 WS2812B是一个集控制电路与发光电路于一体的智能外控LED光源。 其外型与一个5050 LED灯珠相同, 每个元件即为一个像素点。 像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路, 还包含有高精度的内部振荡器和可编程定电流控制部分, 有效保证了像素点光的颜色高度一致。数据协议采用单线归零码的通讯方式, 像素点在上电复位以后, DIN端接受从控制器传输过来的数据, 首先送过来的24bit数据被第一个像素

weixin_43608153的博客 9214

DecorView介绍

01.什么是DecorView DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图。 DecorView作为顶级View,一般情况下它内部包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是标题栏(根据Th...

qijingwang的博客 8423

SAP预扣税配置实战:从BP创建到外部接口集成的完整流程

本文详细拆解了SAP S/4HANA中预扣税配置与集成的完整实战流程。内容涵盖从业务伙伴(BP)架构下的数据存储理解、后台基础配置,到针对批量处理场景,如何绕过标准BAPI,采用直接更新核心表LFBW的策略进行高效开发。最后,文章探讨了与外部接口集成的多种模式与数据流设计,为财务顾问和ABAP开发人员提供了一套清晰、可落地的解决方案。

weixin_29204749的博客 415

医学图像处理实战:3D Slicer从安装到病灶分析全流程指南

本文提供了一份详尽的3D Slicer实战指南,涵盖从软件安装、DICOM数据导入到图像增强、病灶分割及三维可视化的全流程。重点演示了如何利用阈值分割、区域生长等核心图像处理技术进行病灶分析,并生成定量报告,是医学影像分析初学者的实用入门教程。

weixin_29278805的博客 601

安卓页面绘制流程(2)Window和DecorView的创建

讲解DecorView,ViewRootImpl,Window的关系和创建时机。

分享+记录 2540

【推荐算法】召回模型总结

【推荐算法】召回模型总结

m0_48086806的博客 6244

android DecorView

DecorView ,界面的顶级View,他的结构下图所示。DecorView的自己由系统状态栏和LinearLayout组成。 下图的红色圈圈部分,是我们开发时熟知的ViewGroup content=findViewById(android.R.id.content) 部分,content实则是一个Fragment布局,它的子View就是我们的界面布局,可以通过content.getChil...

silence_jjj的专栏 755

Unity URP半透明物体渲染避坑指南:双面渲染与深度写入的实战技巧

本文深入探讨了Unity URP中半透明物体自交叠渲染问题的核心根源与解决方案。针对模型自身交叠导致的排序错误,文章提供了双面渲染与深度写入两种实战技巧,详细分析了其实现原理、性能开销及适用场景,帮助开发者根据项目需求选择最优方案,有效提升玻璃、水体等材质的视觉表现。

sunny的博客 545

AI Agent Harness实时监控大屏搭建实战

本文将以目前主流的AI Agent管控框架Harness为基础,结合React、ECharts、WebSocket技术,手把手带你搭建一套完整的实时监控大屏,覆盖全局概览、状态分布、工具调用统计、异常告警、实时日志等核心功能,不需要复杂的底层开发,复制代码就能快速跑通。本文我们从需求出发,先梳理了AI Agent的核心监控指标,然后搭建了监控大屏的静态布局,逐个实现了各个图表,对接了Harness的实时数据源,最后加了交互和告警功能,完整走了一遍监控大屏从设计到落地的全流程。

大数据洞察的博客 175

Activity、Window、DecorView的关系

在注释(3)可以看到Activity持有PhoneWindow并初始化了PhoneWindow实例,在注释(4)中调用PhoneWindow的setCallback方法将activity实例设置给PhoneWindow,这一点很重要,我们在看DecorView的代码时候,看到的mWindow.getCallback()方法,实际就是获取DecorView相对应的Activity实例。至此,我们知道了在注释(14)中,我们熟悉的activity中的onResume()方法是被。

码龙-的博客 1790

RHEL 8 与 RHEL 7 与 RHEL 6 的比较,RHEL 8强到离谱!

Red Hat Enterprise Linux(RHEL)是企业级 Linux 发行版中最受欢迎的操作系统之一。RHEL 为服务器和企业环境提供了高性能、稳定性和安全性,适用于各种数据中心和云计算平台。自 RHEL 6 以来,Red Hat 对其操作系统进行了多次重大更新,RHEL 7 和 RHEL 8 带来了许多新的特性、工具和架构变化。

网络技术联盟站 708

Android自定义View:绘制前的准备-DecorView创建

前言 回忆前文:Android自定义View基础:ViewRoot、DecorView & Window的简介,可看出最后1步 = 绘制 但在绘制前,系统会有一些绘制准备,即前面几个步骤:创建PhoneWindow类、DecorView类、ViewRootmpl类等 今天,我将主要讲解View绘制前的准备,主要包括:DecorView创建 & 显示,希望你们会喜欢。 1. ...

Carson带你学Android 3015

QT开发技术 [QXlsx 导出大量数据的崩溃大坑]

QXlsx 是一个基于 Qt 框架开发的开源库,用于读写 Excel 文件(.xlsx 格式),无需依赖 Microsoft Office 或第三方库。以下从多个方面为你详细介绍 QXlsx:主要特性读写功能:支持创建、读取和修改 Excel 文件,能处理单元格的数值、公式、格式等基本操作。样式设置:可以设置单元格的字体、颜色、对齐方式、边框等样式,还能创建自定义样式并应用到多个单元格。图表支持:支持创建多种类型的图表,如柱状图、折线图、饼图等,并能对图表的样式和属性进行配置。

weixin_45397344的博客 653

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

android自定义view怎么建,Android自定义View绘制前的准备:DecorView创建 & 显示

前言示意图但在绘制前,系统会有一些绘制准备,即前面几个步骤:创建PhoneWindow类、DecorView类、ViewRootmpl类等今天,我将主要讲解View绘制前的准备,主要包括:DecorView创建 & 显示,希望你们会喜欢。1. DecorView的创建DecorView是显示的顶层View,那么View的绘制准备从DecorView创建开始说起。源码分析DecorView的...

weixin_29013129的博客 365

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

View 自定义 - 概览

从 DecorView 中可以看出 View 的绘制流程开始于ViewRootImpl 对象的 performTraversals(),从视图树根节点(即 DecorView 它是个 ViewGroup)开始由上向下遍历测绘(DecorView→中间层ViewGroup→最底层View)。顶部图中可以看出 ViewRoot 最后一步是绘制,在绘制之前系统会有一些准备,即前面几个步骤:创建PhoneWindow、DecorView、ViewRootmpl。确定控件最终宽高在父容器中的位置。

HugMua的博客 257

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android进阶从零学习自定义View——View树的绘制机制

上篇博客,讲述了一些基本的知识点, 《Android进阶从零学习自定义View——概念基础》 不熟悉的小伙伴,可以先看下上篇博客。 对于工作3-5年的开发者而言,相信绝大部分被问到过这个问题:了解自定义View吗? 这短短的一句话,你可能会说:了解啊,自定义View需要重写onMeasure,onLayout, onDraw三个方法。 没了,没了,对,没下文了, 那这个问题十有八九是跪了,不用想。...

lmq121210的博客 425

自定义View绘制准备-DecorView创建

DecorView源码解析

H_xxxxd的博客 670

闲聊自定义控件之View绘制

了解View的绘制对自定义控件的开发有着重要的意义,上一篇已经对activity加载UI的流程进行了讲解,从中可以看出DecorView是我们的最外层View,是一个FrameLayout的子类,View的绘制也是从DecorView开始的。 DecorView调用performTraversals()方法开始View的绘制,这个方法内容比较多,比较核心的是调用如下方法: - perfor...

遗忘的星星 1208

Android View 绘制流程与自定义 View 全解

Android View 绘制流程与自定义 View 全解

OuO-1 的博客 494

一文了解View的绘制

View的绘制原理

nahfang的博客 842

Android的View体系(二):DecorView的创建与显示

一.DecorView的创建 二.DecorView的显示

微不足道的博客 1630

Carson带你学Android:深入解析自定义View工作流程

今天,我将全面总结自定义View 的全工作流程,我能保证这是市面上的最全面、最清晰、最易懂的

Carson带你学Android 8811

View绘制体系(一)——从setContentView聊起

View绘制体系(一)——从setContentView聊起 前言 对于Android开发者来说,View的绘制流程是最基础的知识,关于View绘制系列博客,我准备从setContentView开始讲解一下View的绘制体系。 setContentView 在Activity中,我们经常会调用到setContentView这个方法来设置对应的布局文件,在这里我想从源码的角度去分析下setCont...

boyeleven的博客 719

Android应用层View绘制流程之DecorView与ViewRootImpl

概述一直对Android中View的整个绘制流程不是很了解,View是怎么添加到Activity当中去的?当View中的内容发生改变的时候是怎样执行界面的刷新的?因此,今天准备从源码的角度来对View的整个绘制流程来进行分析,源码基于API25。由于篇幅限制,这篇文章只分析顶层视图DecorView的显示逻辑,具体的View树绘制三部曲:measure,layout,draw将在下篇博文进行深入剖析

EasyLiu 1189
上一篇: View 自定义 - Activity、Window、DecorView、ViewRoot
下一篇: View 自定义 - 坐标系、位置获取
Jomurphys
博客等级 码龄9年 1768粉丝 261原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值