Android窗口机制:三、Window与Window Manager的创建加载。(源码版本SDK31)

Android 窗口机制 SDK31源码分析 总目录

上一章节我们知道了在调用setContentView方法之后发生的一些列过程,我们可以看到在Activity中已经持有了Window对象,那么他们是如何关联起来的呢?

本章节进行详细的说明。

首先介绍几个类与接口

ViewManager

public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

ViewManager 是一组接口,允许向 Activity 添加和删除子视图的界面。

比如我们常见的ViewGroup就实现了ViewManager,下面将要说到的WindowManager也继承了ViewManager。

WindowManager

//应用程序用来与窗口管理器对话的界面。使用 Context.getSystemService(Context.WINDOW_SERVICE) 获取其中之一。
public interface WindowManager extends ViewManager {
    //则是addView时它的LayoutParams无效则会被抛出,或是添加第二个View的时候没有移除第一个View则会被抛出
	public static class BadTokenException extends RuntimeException{...}
    //如果一个窗口是在一个二级的显示上而指定的显示找不到则会被抛出
    public static class InvalidDisplayException extends RuntimeException{...}
    //返回当前WindowManager管理的显示Display
    public Display getDefaultDisplay();
    //表示从窗口上移除View,一般是当View调用了onDetachedFromWindow也就是从Window上分开后,进行移除
    public void removeViewImmediate(View view);
    //Window的布局参数
    public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable{...}
}

一个接口,继承了ViewManager,所以便可以进行添加或者删除View的操作了。最终的实现类为WindowManagerImpl。

在第一章我们就分析到了,WindowManager的实现类为WindowManagerImpl,但是在WindowManagerImpl内部将所有的操作都委托给了WindowManagerGlobal,这里我们在重复一下,加深印象。

源码分析

好的,接下来进行源码分析,看一下Window、WindowManager和Activity是如何关联起来的吧。

对于SDK31的源码,Activity的启动最终会调用到TransactionExecutor的execute(ClientTransaction transaction)方法,之后会依次调用ActivityThread的handleLaunchActivityhandleStartActivityhandleResumeActivity方法。

对于本次源码分析先省略掉其他步骤,直接到ActivityThread的handleLaunchActivity中查看源码。

ActivityThread
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {
	...
    //初始化WindowManager服务
    WindowManagerGlobal.initialize();
    ...
    //调用performLaunchActivity
    final Activity a = performLaunchActivity(r, customIntent);
    ...
    return a;
}

先初始化了WindowManagerService之后调用了performLaunchActivity

ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //创建与activity的context
    ContextImpl appContext = createBaseContextForActivity(r);
	Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //通过classLoader实例化Activity,支持Activity对象创建出来了。
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        ...
	try {
        //创建/获取Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        //判断获取保留的window
        Window window = null;
        if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
            window = r.mPendingRemoveWindow;
            r.mPendingRemoveWindow = null;
            r.mPendingRemoveWindowManager = null;
        }
        //调用activity的attach方法  
        activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback,
                        r.assistToken, r.shareableActivityToken);
        ...
        //设置主题
        int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
        ...
        //回调Activity的onCreate,通过上一章的分析,我们知道在这里构建了DecorView且并Window持有。
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        //设置生命周期状态
        r.setState(ON_CREATE);
    ...
    return activity;
}

上面的注释还是挺清楚的,我们梳理一下这个方法大概做了什么事情,首先创建当前Activity的Context,通过ClassLoader构建出Activity,然后获取Application,接下来传入了一系列参数调用了Activity的attach方法,最后会调用Activity的onCreate以及设置一些主题生命周期等相关的属性。

所以进入Activity的attach方法,看看做了什么

Activity
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,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
            IBinder shareableActivityToken) {
 	...
    //找到了,实例化Window对象
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(mWindowControllerCallback);
    //设置回调CallBack,上一章节最后getCallback获取到的CallBack就是这时候设置进去的。
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    ...
    //设置UI Thread
    mUiThread = Thread.currentThread();
    //持有ActivityThread对象
    mMainThread = aThread;
    ...
    //有一个重点,给Window对象设置WindowManager
    mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    //持有WindowManager对象,通过Window的getWindowManager获取WindowManager对象
    mWindowManager = mWindow.getWindowManager();
    ...
}

简明扼要,在Activity的attach里面,构建了Window对象被Activity持有,所以我们可以通过getWindow方法获取PhoneWindow。之后将WindowManager传入了Window之中,并且Activity也会持有WindowManager对象,且可以用过getWindowManager获取WindowManager对象。

在ActivityThread的performLaunchActivity方法中我们可以看到,attach的调用结束之后才会回调onCreate方法,所以我们在分析onCreate的setContentView方法里面逻辑的时候,就已经包含了Window对象。至此handleLaunchActivity分析完毕,接下来我们看一下handleStartActivity.

ActivityThread
public void handleStartActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, ActivityOptions activityOptions) {
	...
    //回调onStart方法
    activity.performStart("handleStartActivity");
    r.setState(ON_START);
    ...
    // 最终回调到了onRestoreInstanceState(savedInstanceState)方法
    if (pendingActions.shouldRestoreInstanceState()) {
        if (r.isPersistable()) {
            if (r.state != null || r.persistentState != null) {
                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                                                    r.persistentState);
            }
        } else if (r.state != null) {
            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
        }
    }
    ...
}

看到handleStartActivity里面就是回调了onStart方法,之后会调用到Activity的onRestoreInstanceState用来恢复数据。

最后来看handleResumeActivity方法。

ActivityThread
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {
    ...
    //会判断是否调用onRestart以及调用onResume,并且进行ActivityClientRecord数据更新
    if (!performResumeActivity(r, finalStateRequest, reason)) {
        return;
    }
    ...
    //Window赋值
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        ...
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                //将DecorView与WindowManager通过addView进行绑定,准备进行视图显示
                wm.addView(decor, l);
            }
        }
        ...
        
        r.activity.mVisibleFromServer = true;
        mNumVisibleActivities++;
        if (r.activity.mVisibleFromClient) {
            //DecorView 进行显示
            r.activity.makeVisible();
        }
        ...
}
Activity
//如果mDecor没有被添加到WindowManager则重新添加一次,然后显示DecorView
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

handleResumeActivity中,先进行onRestart以及onResume的调用,之后对windowdecorView的给数据进行赋值,然后将decorView通过WindowManager的addView进行绑定管理。之后进行DecorView的显示。

总结

handleLaunchActivity中进行Activity的实例化,之后初始化WindowManager,Context等,Window持有WindowManager,给Activity绑定Window对象。然后调用到onCreate的setContentView,创建DecorView被Window持有。同时我们自己的布局包含在了DecorView中;之后调用handleStartActivity方法,里面会调用onStart以及onRestoreInstanceState;之后调用handleResumeActivity先回调调用onResume之后将DecorView通过WindowManager的addView方法和WindowManager进行绑定,最后调用Activity的makeVisible进行显示。

好,那么WindowManager的addView究竟干了什么呢?mDecor.setVisibility究竟是怎么显示的呢?具体看下一章节:ViewRootImpl的创建以及视图真正加载。

创作不易,如有帮助一键三连咯🙆‍♀️。欢迎技术探讨噢!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pumpkin的玄学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值