皮皮网
皮皮网

【会员收益系统源码】【新征服源码】【亨特国际源码】android phonewindow源码

来源:燕窝玫瑰三角盏的源码 发表时间:2024-12-28 15:47:45

1.【Android】Window/DecorView/ViewRootImpl
2.Android 14 HWUI 源码研究 View Canvas RenderThread ViewRootImpl skia
3.纯粹的谈谈android.R.id.content
4.❤️ Android 源码解读-从setContentView深入了解 Window|Activity|View❤️
5.android acitivy和window的区别

android phonewindow源码

【Android】Window/DecorView/ViewRootImpl

        根据 Activity启动流程 ,当流程进行到 ActivityThread.performLaunchActivity 的时候,会创建Activity实例,并调用其 attach 方法。在 attach 方法中,会创建Window的实例。

        也就是说,在Activity实例创建之初,Window就已经创建好了。

        DecorView在第一次调用 Window.getDecorView 的时候被创建。PhoneWindow类的 getDecorView 方法实现如下:

        一般情况下,在 onCreate 回调中调用了 setContentView 方法,DecorView就被初始化了。

        调用链为:

        AppcompatActivity.setContentView ->

        AppCompatDelegateImpl.setContentView ->

        AppCompatDelegateImpl.ensureSubDecor ->

        AppCompatDelegateImpl.createSubDecor ->

        PhoneWindow.getDecorView ->

        PhoneWindow.installDecor

        最终,在 PhoneWindow.installDecor 方法中,DecorView被初始化:

        另外,如果不调用 setContentView ,DecorView同样也会在 Activity.performCreate 方法中较后的地方创建。

        ViewRootImpl是在WindowManagerGlobal的 addView 方法中被初始化的,并且也是在这里与DecorView进行绑定,成为DecorView的parent。调用链可以追溯到 ActivityThread.handleResumeActivity 中,在 performResumeActivity 调用之后,ViewRootImpl被创建。

        也就是说,ViewRootImpl是在 onResume 回调之后才进行初始化的。这可以在 onResume 中打印 getWindow().getDecorView().getParent() 证实。

        在 二 中知道了, handleResumeActivity 方法最终会调用 WindowManagerGlobal.addView 方法,在这里 ViewRootImpl 被创建,并且通过 setView 方法绑定DecorView,这些都发生在onResume之后。

        在ViewRootImpl的 setView 方法中,又会调用 requestLayout ,在这里就会进行这个View树的第一次测绘。具体的方式是通过 scheduleTraversals 方法向 Choreographer 发送一个预定的消息,并在下一次屏幕刷新的时候调用 doTraversal → performTraversals 方法进行ViewTree的测量、布局和绘制。

        从这一点我们可以知道,在Activity的 onResume 或之前的生命流程中调用View的 getMesuredWidth 或者 getWidth 都会返回0,因为这个时候还没有开始测量。

        当View树还没有被测绘的时候,View.post会将这个Runnable发送给内部的一个消息队列(不是系统的消息队列)。这个消息队列中保存的Runnable会在下一次 performTraversals 的时候被执行;调用链为:

        ViewRootImpl.performTraversals →

        DecorView.dispatchAttachedToWindow →

        ... →

        View.dispatchAttachedToWindow →

        executeActions

        最终在 executeActions 方法中,Runnable对象被发送给ViewRootImpl的内部Handler执行。也就是说,当这个Runnable被执行的时候,已经至少经过一次测绘了,所以可以正确的获取到View的宽高;也说明了为什么通过 View.post 发送的Runnable会在主线中执行。

        当View树已经被测绘过了, View.post 就会直接通过内部的 mHandler 发送消息,这个Handler是在attach的过程中跟着 AttachInfo 一起传递给View的,实质上就是ViewRootImpl的内部Handler。

Android HWUI 源码研究 View Canvas RenderThread ViewRootImpl skia

       HUWUI是源码Android系统中负责应用可视化元素绘制的核心组件,其架构主要在C++层实现,源码从Java层接收View绘制信息,源码通过唯一的源码渲染线程使用skia技术完成渲染任务。整体上,源码从应用程序到UI线程,源码会员收益系统源码再到渲染线程,源码形成了清晰的源码层级关系。

       HUWUI的源码构建主要包括三个核心类,它们分别是源码:RecordingCanvas、Canvas、源码RenderNode、源码RenderProxy、源码RenderThread、源码CanvasContext、源码IRenderPipeline。在Java层,新征服源码主要涉及两类Canvas,RecordingCanvas用于记录绘制指令,Canvas则是直接用于渲染。RecordingCanvas在构造时创建,而Canvas在调用时创建。这两个类在C++层分别对应SkiaRecordingCanvas和SkiaCanvas,后者直接引用SkCanvas。

       在全局循环中,UI线程与渲染线程之间的协同操作至关重要。具体流程包括:新创建Activity后,附着到对应的PhoneWindow,然后调用PhoneWindow的setContentView方法,将View添加到DecorView作为子节点。接着,DecorView与ViewRootImpl对接,完成View的亨特国际源码更新与渲染。整个过程包含了measure、layout和draw等复杂子流程。

       渲染线程创建与核心对象紧密关联,主要包括RenderProxy、RenderThread和DrawFrameTask。RenderProxy负责Java层信息的衔接,RenderThread作为进程唯一的渲染线程,持有DrawFrameTask和CanvasContext,完成一帧的绘制任务。指令记录流程的核心在于使用C++层的RecordingCanvas将View属性和绘制信息记录到DisplayList中,进而完成指令的渲染。

       Surface、ANativeWindow、EGLSurface的创建流程在ViewRootImpl的performTraversals函数中初始化。ReliableSurface的封装和EGL与Skia环境的创建主要在RenderThread的requireGlContext函数中实现。从源码分析,discuz主页源码这一过程通常在三个地方调用。

       View树与RenderNode树之间的协作关系明确,一个Application进程对应多个Activity,每个Activity与一个PhoneWindow绑定,PhoneWindow持有DecorView,DecorView对应一个ViewRootImpl,而ViewRootImpl与ThreadedRender模块对接。ThreadedRender与C++层的RenderProxy一一对应,RenderProxy持有关键对象,如RenderThread、CanvasContext、DrawFrameTask等。RenderThread是单例模式,进程唯一,负责一帧绘制的逻辑。

       在RenderPipeline模块中,直播解析源码关键操作包括makeCurrent、draw和swapBuffers。Native Canvas在这一过程中扮演了桥梁角色,接收Java API调用,而RecordingCanvas完成Op记录,最终DisplayListData存储这些Op。

       skia的核心资源主要在三个使用场景中发挥作用,具体细节需深入分析,这些资源对于实现高效、稳定的渲染效果至关重要。

纯粹的谈谈android.R.id.content

       æˆ‘们在Activity.onCreate中执行setContentView,其实是往Window里面进行setContentView

        注解1:getWindow()获取的是mWindow,而mWindow在attach的时候,初始化为PhoneWindow

        注解1:如果mDecor也就是DecorView不存在,就创建一个DecorView,也就是执行注解2

        注解3:如果mContentParent不存在,就使用mDecor创建一个mContentParent,也就是执行注解4

        注解1:layout就定义了content id

        注解2:mDecor把资源文件addView到本身View中

        注解3:Window.java中有定义变量ID_ANDROID_CONTENT = com.android.internal.R.id.content;

        我们看findViewById

        注解1:getDecorView是从DecorView中获取android.R.id.content

        总结,android.R.id.content来自DecorView,但是这个仅仅是DecorView的一个子View。

        这里了解到它是子View之后,很多事情就需要注意了,例如title的去除等等

❤️ Android 源码解读-从setContentView深入了解 Window|Activity|View❤️

       Android系统中,Window、Activity、View之间的关系是紧密相连且相互作用的。了解这三者之间的关系,有助于深入理解Android应用的渲染和交互机制。

       在Android中,通常在创建Activity时会调用`setContentView()`方法,以指定显示的布局资源。这个方法主要作用是将指定的布局添加到一个名为`DecorView`的容器中,并最终将其显示在屏幕上。这一过程涉及到多个组件的交互,下面分步骤解析。

       在`Activity`类中,`setContentView()`方法调用`getWindow()`方法获取`Window`对象,而`Window`对象在`Activity`的`attach()`方法中被初始化。`Window`对象是一个抽象类,其默认实现为`PhoneWindow`,这是Android特定的窗口实现。

       `PhoneWindow`在创建时会通过`setWindowManager()`方法与`WindowManager`进行关联。`WindowManager`是系统级组件,用于管理所有的窗口,包括窗口的创建、更新、删除等操作。`WindowManager`的管理最终由`WindowManagerService`(WMS)执行,这是一个运行在系统进程中的服务。

       在`PhoneWindow`中,`installDecor()`方法会初始化`DecorView`和`mContentParent`。`mContentParent`是一个`ViewGroup`,用于存放`setContentView()`传入的布局。通过`mLayoutInflater`的`inflate()`方法,将指定的布局资源添加到`mContentParent`中。

       `DecorView`是一个特殊的`FrameLayout`,包含了`mContentParent`。在完成布局的添加后,`DecorView`本身并没有直接与`Activity`建立联系,也没有被绘制到屏幕上显示。`DecorView`的绘制和显示发生在`Activity`的`onResume()`方法执行后,这时`Activity`中的内容才真正可见。

       当`Activity`执行到`onCreate()`阶段时,其内容实际上并没有显示在屏幕上,直到执行到`onResume()`阶段,`Activity`的内容才被真正显示。这一过程涉及到`ActivityThread`中的`handleResumeActivity()`方法,该方法会调用`WindowManager`的`addView()`方法,将`DecorView`添加到`WindowManagerService`中,完成`DecorView`的绘制和显示。

       `WindowManagerService`通过`addView()`方法将`DecorView`添加到显示队列中,并且在添加过程中,会创建关键的`ViewRootImpl`对象,进一步管理`DecorView`的布局、测量和绘制。`ViewRootImpl`会调用`mWindowSession`的`addToDisplay()`方法,将`DecorView`添加到真正的显示队列中。

       `mWindowSession`是`WindowManagerGlobal`中的单例对象,其内部实际上是一个`IWindowSession`类型,通过`AIDL`接口与系统进程中的`Session`对象进行通信,最终实现`DecorView`的添加和显示。

       通过`setView()`方法的实现,可以看到除了调用`IWindowSession`进行跨进程添加`View`之外,还会设置输入事件处理。当触屏事件发生时,这些事件首先通过驱动层的优化计算,通过`Socket`跨进程通知`Android Framework`层,最终触屏事件会通过输入管道传送到`DecorView`处理。

       在`DecorView`内部,触屏事件会通过`onProcess`方法传递给`mView`,即`PhoneWindow`中的`DecorView`。最终,事件传递到`PhoneWindow`中的`View.java`实现的`dispatchPointerEvent()`方法,并调用`Window.Callback`的`dispatchTouchEvent(ev)`方法。对于`Activity`来说,`dispatchTouchEvent()`方法最终还是会调用`PhoneWindow`的`superDispatchTouchEvent()`,然后传递给`DecorView`的`superDispatchTouchEvent()`方法,完成事件的分发和处理。

       综上所述,通过`setContentView()`的过程,我们可以清晰地看到`Activity`、`Window`、`View`之间的交互关系。整个过程主要由`PhoneWindow`组件主导,而`Activity`主要负责提供要显示的布局资源,其与屏幕的直接交互则通过`WindowManager`和`WindowManagerService`实现。

android acitivy和window的区别

       æˆ‘想大多数人,对于这3个东西的概念能区分,但是具体区别在哪却很难说出来。

       æˆ‘这里根据我个人的理解来讲讲我个人对这3个概念的理解。当然这里设计到通用的事件窗口模型等通用GUI设计,我这里就不打算讲了,纯粹从概念上来进行区分。

       Activity是Android应用程序的载体,允许用户在其上创建一个用户界面,并提供用户处理事件的API,如onKeyEvent, onTouchEvent等。 并维护应用程序的生命周期(由于android应用程序的运行环境和其他操作系统不同,android的应用程序是运行在框架之内,所以他的应用程序不能当当从进程的级别去考虑,而更多是从概念上去考虑。android应用程序是由多个活动堆积而成,而各个活动又有其独立的生命周期)。Activity本身是个庞大的载体,可以理解成是应用程序的载体,如果木有Activity,android应用将无法运行。也可以理解成android应用程序的入口。Acivity的实例对象由系统维护。系统服务ActivityManager负责维护Activity的实例对象,并根据运行状态维护其状态信息。

       ä½†åœ¨ç”¨æˆ·çº§åˆ«ï¼Œç¨‹åºå‘˜å¯èƒ½æ ¹æ„¿æ„ç†è§£æˆä¸ºä¸€ä¸ªç•Œé¢çš„载体。但仅仅是个载体,它本身并不负责任何绘制。Activity的内部实现,实际上是聚了一个Window对象。Window是一个抽象类,它的具体是在android_src_home/framework/policies/base/phone/com/android/internal/policy/impl目录下的PhoneWindow.java。

       å½“我们调用Acitivity的 setContentView方法的时候实际上是调用的Window对象的setContentView方法,所以我们可以看出Activity中关于界面的绘制实际上全是交给Window对象来做的。绘制类图的话,可以看出Activity聚合了一个Window对象。

       ä¸‹é¢æ˜¯PhoneWindow中的setContentView方法的实现:

        @Override

        public void setContentView(View view, ViewGroup.LayoutParams params) {

        if (mContentParent == null) {

        installDecor();

        } else {

        mContentParent.removeAllViews();

        }

        mContentParent.addView(view, params);

        final Callback cb = getCallback();

        if (cb != null) {

        cb.onContentChanged();

        }

        }

       Window内部首先判断mContentParent是否为空,然后调用installDecor方法(安装装饰器),我们看看这个方法如何实现的

        private void installDecor() {

        if (mDecor == null) {

        mDecor = generateDecor();

        mDecor.setIsRootNamespace(true);

        }

        if (mContentParent == null) {

        mContentParent = generateLayout(mDecor);

        mTitleView = (TextView)findViewById(com.android.internal.R.id.title);

        if (mTitleView != null) {

        if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {

        View titleContainer = findViewById(com.android.internal.R.id.title_container);

        if (titleContainer != null) {

        titleContainer.setVisibility(View.GONE);

        } else {

        mTitleView.setVisibility(View.GONE);

        }

        if (mContentParent instanceof FrameLayout) {

        ((FrameLayout)mContentParent).setForeground(null);

        }

        } else {

        mTitleView.setText(mTitle);

        }

        }

        }

        }

       åœ¨è¯¥æ–¹æ³•ä¸­ï¼Œé¦–先创建一个DecorView,DecorView是一个扩张FrameLayout的类,是所有窗口的根View。我们在Activity中调用的setConctentView就是放到DecorView中了。这是我们类图的聚合关系如下:

       Activity--->Window--->DecorView

       è¿™æ˜¯æˆ‘们得出这3个类之间最直接的一个关系。

       æˆ‘们详细分析一下,类对象是如何被创建的。

       å…ˆä¸è€ƒè™‘Activity的创建(因为 Acitivity的实例由ActivityManager维护,是在另一个进程设计到IPC的通信,后面会讲到),而考虑Window和View的创建。

       Activity被创建后,系统会调用它的attach方法来将Activity添加到ActivityThread当中。我们找到Activity的attach方法如下:

       final void attach(Context context, ActivityThread aThread,

        Instrumentation instr, IBinder token, int ident,

        Application application, Intent intent, ActivityInfo info,

        CharSequence title, Activity parent, String id,

        Object lastNonConfigurationInstance,

        HashMap<String,Object> lastNonConfigurationChildInstances,

        Configuration config) {

        attachBaseContext(context);

        mWindow= PolicyManager.makeNewWindow(this);

        mWindow.setCallback(this);

        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {

        mWindow.setSoftInputMode(info.softInputMode);

        }

        mUiThread = Thread.currentThread();

        mMainThread = aThread;

        mInstrumentation = instr;

        mToken = token;

        mIdent = ident;

        mApplication = application;

        mIntent = intent;

        mComponent = intent.getComponent();

        mActivityInfo = info;

        mTitle = title;

        mParent = parent;

        mEmbeddedID = id;

        mLastNonConfigurationInstance = lastNonConfigurationInstance;

        mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;

        mWindow.setWindowManager(null, mToken, mComponent.flattenToString());

        if (mParent != null) {

        mWindow.setContainer(mParent.getWindow());

        }

        mWindowManager = mWindow.getWindowManager();

        mCurrentConfig = config;

        }

       æˆ‘们看红色的代码部分,就是创建Window对象的代码。感兴趣的同学可以跟踪去看看具体是如何创建的。其实很简单,其内部实现调用了Policy对象的makeNewWindow方法,其方法直接new了一个PhoneWindow对象如下:

       public PhoneWindow makeNewWindow(Context context) {

        return new PhoneWindow(context);

        }

       è¿™æ—¶æˆ‘们已经可以把流程串起来,Activity创建后系统会调用其attach方法,将其添加到ActivityThread当中,在attach方法中创建了一个window对象。

       ä¸‹é¢åˆ†æžView的创建。我们知道Window聚合了DocerView,当用户调用setContentView的时候会把一颗View树仍给DocerView.View树是已经创建好的实例对象了,所以我们研究的是DocerView是个什么东西,它是如何被创建的。

       æˆ‘们回头看看Window实现里边的setContentView方法,我们看上面代码的红色部分setContentView-> installDecor-> generateDecor.

       generateDecor直接new了一个DecorView对象:

       protected DecorView generateDecor() {

        return new DecorView(getContext(), -1);

        }

       æˆ‘们可以去看看DecorView的实现,它是PhoneWindow的一个内部类。实现很简单,它默认会包含一个灰色的标题栏,然后在标题栏下边会包含一个空白区域用来当用户调用setContentView的时候放置用户View,并传递事件,这里不做详细分析,感兴趣同学可以自己研究研究。

       å½“DecorView创建好之后再回到Window中的setContentView方法中来,见上面代码蓝色部分,调用

        mContentParent.addView(view, params);

       æ¥å°†ç”¨æˆ·çš„View树添加到DecorView中。

       åˆ°è¿™æ—¶ä¸ºæ­¢ï¼Œæˆ‘想我们已经很清晰的认识到它们3者之间的关系,并知道其创建流程。

       çŽ°åœ¨æ€»ç»“一下:

       Activity在onCreate之前调用attach方法,在attach方法中会创建window对象。window对象创建时并木有创建Decor对象对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的View 添加到DecorView中。

相关栏目:焦点