Android Framework 之 Window / Win

2022-11-21  本文已影响0人  行走中的3卡

View 是依附在 Window 上,是不能单独存在的。
因此,需要了解各种View(广义上的) 如 Activity / Dialog /Toast 等,创建各自Window的过程.

这里介绍 Activity 的 Window 的创建过程.

1. Activity 的创建

在 ActivityThread 中创建 Activity

//ActivityThread.java
package android.app;

public final class ActivityThread extends ... {

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent); //(1)
        ...
        
         if (activity != null) {
             activity.attach(appContext, this,...); //(2)
         }

分析:
(1) 在 performLaunchActivity 中, 通过 类加载器 创建 activity
(2) 然后调用 activity.attach(),这里将会 创建Window

2. 创建 Window

//Activity.java
package android.app;

@UiContext
public class Activity extends ContextThemeWrapper..{

    final void attach(Context context, ActivityThread aThread,...) {
        mWindow = new PhoneWindow(this, window, activityConfigCallback);//(1)
        mWindow.setWindowControllerCallback(mWindowControllerCallback);//(2)
        mWindow.setCallback(this);
        
        mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),..);//(4)

        mWindowManager = mWindow.getWindowManager();//(4)
    }       
        
    public Window getWindow() {//(3)
        return mWindow;
    }

    public WindowManager getWindowManager() {//(4)
        return mWindowManager;
    }
    

分析:
(1) 在 attach 方法中, 创建了 PhoneWindow 对象
(2) 设置了callback,即后续 Window 的 回调可以 通知到 该 activity 对象.
(3) 提供了 getWindow() 接口获取 Window 对象.
(4) 获取 WindowManager 并设置给 Window 对象,然后再通过 Window接口获取,Activity 也提供接口.

2. 设置视图内容 setContentView

Activity.attach() 会创建 Window, 还需要把 布局内容 添加 DecorView中.
最终也会调用 Window 的 setContentView.

//Activity.java
package android.app;
public class Activity extends ContextThemeWrapper..{

    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        ...
    }

显然,还是要看 PhoneWindow 的实现.

package com.android.internal.policy;

public class PhoneWindow extends Window ... {
    private DecorView mDecor;
    
    ViewGroup mContentParent;
    
    @Override
    public void setContentView(int layoutResID) { //(1)
        if (mContentParent == null) { //(2) 
            installDecor();//(2) 
        } ...

        ...
        mLayoutInflater.inflate(layoutResID, mContentParent);//(5)
    }

    private void installDecor() {
        if (mDecor == null) { //(3)-1
            mDecor = generateDecor(-1); //(3)-2
            ...
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
    }

    protected DecorView generateDecor(int featureId) {
        ....
        return new DecorView(context, featureId, this, getAttributes());//(3)-3
    }
    
}

分析:
(1) setContentView 的参数为 layoutResID, 即布局文件的id
(2) 判断 mContentParent 是否为空,如果是,则会调用 installDecor.
(3) installDecor 又会判断 mDecor 是否为空,如果是则调用 generateDecor 创建DecorView对象
(4) mContentParent 为空,则会调用 generateLayout 创建, 传入的参数为 非空的 DecorView 对象.
(5) 将布局资源即layoutResID指定的文件 , 添加到 mContentParent 即 父ViewGroup

3. 将 DecorView 添加到 Window 中.

经过上面的1和, DecorView 已创建, 并且 布局资源 也添加 到了 mContentParent.
但是, 此时 DecorView 还没被 WindowManager 添加到 Window 中.

先要在 ActivityThread 的 handleResumeActivity 中,调用 activity.onResume.
接着在 将 DecorView 添加到 Window 中.

//ActivityThread.java
package android.app;

public final class ActivityThread extends ... {

    @Override
    public void handleResumeActivity(ActivityClientRecord r ..) {//(1)
        ...
        if (!performResumeActivity(r, finalStateRequest, reason)) { //(2)
            return;
        }
        ...
        final Activity a = r.activity; //(3)
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow(); // (4)
            View decor = r.window.getDecorView(); // (5)
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager(); //(6)
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;//(7)
            ..
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l); //(8)
                }..
            }
}           

分析:
(1) handleResumeActivity 里的参数 r 是 ActivityClientRecord 对象, 包含 activity 的信息
(2) 主要执行 回调函数 activity.onResume
(3) 获取当前 activity 实例对象
(4) 将 activity 的 Window 赋值给 r.window
(5) 通过 activity 的 window 获取到 decorView
(6) 通过 activity 获取 ViewManager (即WindowManager )对象,
从2-(4) 的分析,可以知道,其实是通过 mWindow.getWindowManager 获取的.
(7) 更新 activity 的 mDecor
(8) 真正 调用 WindowManager 添加 DecorView. 这里就回到之前讲过的知识上了.

参考文献:
https://juejin.cn/post/7076274407416528909#heading-25

-- End --

上一篇 下一篇

猜你喜欢

热点阅读