android笔记之Window

前言

    这几天开始看Window相关的内容,会把相关的东西记录在这儿,以备以后查阅。内容及内容结构会逐步迭代完善。

1. Window是抽象基类,只有PhoneWindow一个抽象基类

    android.jar中的Window声明:

public abstract class Window {
    ...
}

    Window的类结构示意图:

Window类结构示意图.png

    Window类声明说明确实是抽象基类,Window结构示意图说明确实只有PhoneWindow实现类。

2. 官方文档中对Window的介绍

Abstract base class for a top-level window look and behavior policy.
An instance of this class should be used as the top-level view added to the window manager. 
It provides standard UI policies such as a background, title area, default key processing, etc.

    翻译过来的意思是,

Window,一个负责管理窗口显示、定义行为交互策略的顶层抽象基类;
Window的实例对象应该被当做最顶层的View添加到WindowManager中;
Window,提供了一套诸如背景设置、title区域设置、默认输入事件处理等标准的UI显示及行为处理策略

3. WindowManager

    源码中的WindowManager中的声明:

public interface WindowManager extends ViewManager {
    ...
}

    可见,WindowManager是一个接口,并继承ViewManager接口。ViewManager中声明就很简单了:

public interface ViewManager
{
    //添加view
    public void addView(View view, ViewGroup.LayoutParams params);
    //更新View的布局
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    //移除View
    public void removeView(View view);
}

    主要的操作是:添加View、更新View、移除View。下面看一下WindowManager的类继承结构:

WindowManager类结构示意图.png

    与Window的类继承结构类似,WindowManager也只有一个实现类,WindowManagerImpl。查看WindowManagerImpl的构造方法被调用的地方,发现在WindowManagerImpl类之外,只有一个地方创建了WindowManagerImpl对象:

package android.app;
final class SystemServiceRegistry {
    ...
    static {
        ...//此处省略大量registerService方法调用
        registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
        ...//此处省略大量registerService方法调用
    }
    ...
}

    这也就是注册系统服务的地方了,此处注册的是WINDOW_SERVICE,获取该Window服务,可通过Context.getSystemService(Context.WINDOW_SERVICE)。SystemServiceRegistry类中的该static代码块中有大量注册服务(registerService)代码,再结合该类中的其他方法诸如createServiceCache、getSystemService,基本可以推测出SystemServiceRegistry此类就是用来做系统服务的注册和获取的。

    既然说到了这里,那就继续探究一下SystemServiceRegistry的静态代码块什么时候会被调用呢?先看一下SystemServiceRegistry被调用的地方,如下图:

SystemServiceRegistry被调用示意图.png

    如图所示,只有一个叫做ContextImpl的类中使用了SystemServiceRegistry。看到ContextImp就能想到很多了,比如这张清晰明了的Context继承关系示意图:

Context类继承结构示意图.png

    再比如说,ContextWrapper只是提供方法,这些方法的具体实现其实都是在ContextImpl中。再来看一下ContextImpl调用SystemServiceRegistry的那几个方法,一个createXXX,两个getXXX。看一下createXXX方法就可以了:

class ContextImpl extends Context {
    ...
    // The system service cache for the system services that are cached per-ContextImpl.
    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
    ...
}

    上述代码非常清晰地显示了SystemServiceRegistry.createXXX()方法在创建ContextImpl对象给其成员变量mServiceCache初始化时就会被调用。而另外两个getXXX方法,都是在ContextImpl的具体方法中调用的,当然在初始化成员变量的SystemServiceRegistry.createXXX()较另外两个getXXX方法先被执行,执行时也就是SystemServiceRegistry类被导入到内存时。也就是说在ContextImpl对象初始化时,SystemServiceRegistry类会被导入内存,进而执行SystemServiceRegistry的static代码块。那么最早的ContextImpl对象是在什么时候创建的呢?

    我们知道Application也是一种Context,Context的衍生子类中有Application。查看ActivityThread中创建application一步一步走下去会看到下面这段代码,证实了创建Application对象时也会创建ContextImp对象:

package android.app;
public final class LoadedApk {
    ...
    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        ...
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
        ...
    }
    ...
}

    所以,基本可以推测,SystemServiceRegistry的静态方法最先执行是在app启动创建Application对象的时候。

    废话有点儿多,言归正传,继续说Window。

4. WindowManagerService

    WindowManagerService是framework层的窗口管理服务,管理的是系统中全部Window。运行在一个非app进程的进程内(基本可以确定是SystemServer进程内),是用于接收来自于app进程window操作信息的binder线程。一次可管理多个Window。

    查资料时查到了对窗口本质的一段描述,里面也涉及到了WindowManagerService,所以就写在这个小标题下面了:Window的本质是一块显示区域,在android中就是可绘制的画布:surface,当surface显示到屏幕上之后就是我们看到的Window了。WindowManagerService添加Window,其实就是在为app分配Surface,WindowManagerService还能够管理各个Window,使其有序地排列在屏幕上。

    什么是android的显示系统呢?上面这篇资料也给出了解释并给了图,个人认为非常清晰明了:

android显示系统.png

    上图中非常清晰地介绍了android显示系统三个层次各自的职责范围。另外,app进程中的Window也属于系统中的窗口,也需要WindowManagerService(管理系统中所有的Window)去管理,这就需要app进程与WindowManagerService进行跨进程通信了。还有,这里第一次看到SurfaceFlinger,原来是它将Surface显示到屏幕上的,这就是android系统的surface机制。

    下面是WindowManagerService在android.jar中的声明:

package com.android.server.wm;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
        ...
}

    因为@hide的存在,所以这个类一般在android.jar中是不可见的,可以通过替换jar包显示出来。另外看到Stub应该可以联想出来一些Binder相关的内容:

public interface IMyAidlInterface extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements IMyAidlInterface {
        ...
        public static IMyAidlInterface asInterface(android.os.IBinder obj) {
            ...
        }
        ...
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }
        ...
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            ...
        }
        ...
        private static class Proxy implements IMyAidlInterface {
            Proxy(android.os.IBinder remote) {
                ...
            }
            ...
            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }
            ...
            //在某个方法中调用mRemote.transact方法
            ...
        }
        ...
    }
}

    上面这段代码基本就是Binder通信代码部分的基本结构了:IMyAidlInterface为接口并继承IInterface接口,Stub为IMyAidlInterface的静态抽象内部类并继承Binder、实现IMyAidlInterface,Proxy为Stub的静态内部类并实现IMyAidlInterface。另外,Stub中onTransact方法用来接收跨进程传来的信息,Proxy中调用transact用来向别的进程传递信息。

    那下面看一下,WindowManagerService的声明

package com.android.server.wm;

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
        ...
}

    IWindowManager的声明及简单结构

package android.view;

public interface IWindowManager extends android.os.IInterface {
    static abstract class Stub extends android.os.Binder implements android.view.IWindowManager {
        ...
        public android.os.IBinder asBinder() {
            ...
        }
        ...
        public boolean onTransact(int i, android.os.Parcel parcel, android.os.Parcel parcel1, int i1) throws android.os.RemoteException {
            ...
        }
        ...
        private static class Proxy implements android.view.IWindowManager {
            ...
            Proxy(android.os.IBinder iBinder) {...}
            ...
            public android.os.IBinder asBinder() { ... }
            ...
        }
    }
}

    有没有发现IWindowManager代码结构与IMyAidlInterface代码结构十分相似?只不过WindowManagerService继承了Stub,单独写成了一个独立的类。对的,它们本来就都是Binder机制,当然要相似。我想说的是,我们懂得Binder代码基本结构(就是,IMyAidlInterface的代码结构)各个部分的功能,那也就能够类比出WindowManagerService机制中哪些方法是用来接收信息,哪些方法是用来组装pacel发送信息的,哪些方法是用来判断当前binder是否为本进程对象的

    WindowManagerService、ActivityManagerService、ApplicationThread等通信机制,其实都是binder机制,代码层次结构、继承关系都符合binder机制的基本代码结构(IMyAidlInterface的代码结构)。通过类比的方式,理解起这些通信机制就容易很多。

5. window的分类

    Window分为三类:应用窗口(application window)、子窗口(sub window)、系统窗口(System Widow)。

  • 应用窗口:就是一般app的窗口,Activity对一个的窗口。
  • 子窗口:不能单独存在的窗口,需要依附在特定的父窗口中,比如popupWindow、菜单弹出框(Menu);
  • 系统窗口:系统级别的窗口,比如说ANR时的系统异常窗口、系统状态栏、屏保窗口、toast窗口、输入法窗口、壁纸窗口等。在使用时需注意,有些系统窗口需要相关权限。

    那这些窗口类型在代码中怎么设置呢?通过WindowManager.LayoutParams中type字段进行设置。先看一下,WindowManager.LayoutParams

public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
    ...
}

    继承了ViewGroup.LayoutParams实现Parcelable,主要作用是设置Window的布局参数。看了此type的文档之后,你会发现上面所述的三种类型并不是对应三个type而是对应3个type范围。

窗口类型 type取值范围
应用窗口 1 ~ 99,FIRST_APPLICATION_WINDOW~LAST_APPLICATION_WINDOW
子窗口 1000 ~ 1999,FIRST_SUB_WINDOW~LAST_SUB_WINDOW
系统窗口 2000 ~ 2999,FIRST_SYSTEM_WINDOW~LAST_SYSTEM_WINDOW

    每一个Window都对应z-ordered,type值大的Window会覆盖type值小的Window。另外,WindowManager.LayoutParams中定义了许多type常量,想要对这些type有一个整体的了解的话,可以参看这篇文章的“Window分类”部分。

6. Activity创建过程中,Window、WindowManager所起的作用

    1. Activity回调onCreate之前

    Activity是怎么创建的呢?整个过程是怎样的呢?从调用Activity的startActivity开始,继而执行Instrumetation的execStartActivity,然后通过Binder机制,app进程中的ActivityThreadProxy与SystemServer进程中的ActivityManagerService进行通信告知要启动一个Activity,ActivityManagerService通过同进程的ApplicationThreadProxy与app进程中的ApplicationThread进行通信告知要启动一个Activity,ApplicationThread通过ActivityThread的mh这个Handler对象发送一个类型为“LAUNCH_ACTIVITY”消息给UI主线程,UI主线程取出消息,开始为显示一个Activity做准备。

    经过上面的这些过程,之后会执行到ActivityThread的performLaunchActivity方法:

package android.app;

public final class ActivityThread {
    ...
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
       ...
       //使用ClassLoarder反射出Activity对象
       Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ...
        }
        try {
            //创建Application对象,里面有已创建就不再去创建的逻辑
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            if (activity != null) {
              
              //创建当前Activity的Context对象
              Context appContext = createBaseContextForActivity(r, activity);
              
              ...//配置相关
              
            //初始化Window
            ...//Window的一些标记
            //activity的attach方法就是创建Window对象的地方
            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);
            }
            ...
            //设置主题
            int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
            
            //回调onCreate方法
            activity.mCalled = false;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            ...
            if (!r.activity.mFinished) {
                activity.performStart();//在这里面会回调onStart方法
                r.stopped = false;
            }
            ...
            
        }} catch (SuperNotCalledException e) {
            ...
        } catch (Exception e) 
            ...
        }
       ...
    }
    ...
}

    由上述源码可知,这个performLaunchActivity做的事情还是挺多的,创建Activity 对象,创建Applciation对象,创建Context对象,初始化Window对象,以及回调activity对象的onCreate、onStart方法。
    activity中的attach方法的完整源码

package android.app;
public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
        ...
        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) {
        //把在performLaunchActivity中创建的Context对象绑定的ContextWrapper类中的mBase变量上
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        
        // 创建PhoneWindow对象,一个Activity对应的那一个PhoneWindow
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        //窗口事件的回调方法,文档中说,这个Callback用于拦截key事件和窗口中其他动态操作
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        //设置窗口的软键盘模式相关
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        //将主线程记录在Activity的mUiThread
        mUiThread = Thread.currentThread();

        //记录ActivityThread对象以及给Activity的很多变量进行初始化
        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }
        
        //为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());
        }
        //Window中记录了WindowManager对象,Activity也记录了一下
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }
        ...
}

    根据上述源码可以知道,Activity的attach方法主要做了这些事情:给ContextWrapper中的成员变量mBase赋值、创建Window对象并设置回调函数,给Activity的众多成员变量赋值,为Window设置WindowManager对象等。

    下面看一下,Window的setWindowManager方法:

package android.view;
public abstract class Window {
    ...
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
        //为window中的一些变量赋值
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        //在现有WindowManager的基础上又创建了WindowManager对象
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
    ...
}

    在为Window设置WindowManager的过程中,其实有两个WindowManager对象,一个是通过getSystemService(Context.WINDOW_SERVICE)获取到的,另一个是通过第一个得到的WindowManager对象调用createLocalWindowManager方法获取的。这两个WindowManager对象的不同在于,第二个的成员变量mParentWindow是有值的,最终负责管理Window的也是第二个WindowManager对象。

    2. Activity回调onCreate

    在上面介绍performLaunchActivity方法做的事情时,说它在执行了activity.attach方法之后会回调Activity对象的onCreate方法。在onCreate方法一般会调用setContentView方法,那setContentView背后到底做了哪些事呢?
    Activity的setContentView方法(AppcompatActivity这里就不说了,和Activity的setContentView是有差异的):

package android.app;
public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
    ...
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    ...
    public Window getWindow() {
        return mWindow;
    }
    ...
}

    可以看到,getWindow方法直接返回了mWindow,而它赋值的地方就是在Activity的attach方法中:mWindow = new PhoneWindow(this, window)。也就是说,Activity的setContentView方法其实就是去调用PhoneWindow的setContentView方法,那就去看一下PhoneWindow的setContentView的方法:

package com.android.internal.policy;
public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ...
    @Override
    public void setContentView(int layoutResID) {
        //DecorView分为两部分:标题和内容。内容其实就是这里的mContentParent
        //mContentParent为空说明还没有DecorView,那就去创建DecorView
        //非空的话,要移除所有的布局,因为要给它设置新的布局(layoutResID)了
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        //因为执行了上面的代码,到这里mContentParent就不为空了
        
        // 如果内容显示时需要动画就执行Scence相关代码,否则就直接使用填充器填充就可以了
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        
        //执行到这里mContentParent就已经填充了layoutResID中的内容了
        
        //让DecorView的内容区域延伸到systemUi下方,防止在扩展时被覆盖,达到全屏、沉浸等不同体验效果(并不是很理解)
        mContentParent.requestApplyInsets();
        //回调Callback中的onContentChanged方法
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }
    ...
}

    可见window的setContentView方法做的事情是:没有DecorView就创建DecorView,把布局内容放到mContentParent中,然后回调窗口的onContentChanged方法。

    3. Activity回调onResume

    上面说了performLaunchActivity的方法,这里看一下,ActivityThread中调用performLaunchActivity的地方:handleLaunchActivity

package android.app;
public final class ActivityThread {
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ...
        //初始化WindowManagerGlobal
        WindowManagerGlobal.initialize();
        //这里就是调用performLaunchActivity的地方,上面已经讲述了该方法的功能
        Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            ...
            //在这里会回调Activity对象的onResume方法
            handleResumeActivity(r.token, false, r.isForward,
                        !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            ...
        }else{
            ...
        }
        ...
    }
    
    ...
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ...
        //真正回调onResume的方法
        r = performResumeActivity(token, clearHide, reason);
        if (r != null) {
            ...
            if (r.activity.mVisibleFromClient) {
                //这里的makeVisible方法就是使界面显示的方法了
                r.activity.makeVisible();
            }
            ...
        }
        ...
    }
    ...
}

    Activity的makeVisible方法:

package android.app;
public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
    ...
    void makeVisible() {
        if (!mWindowAdded) {
            //获取WindowManager
            ViewManager wm = getWindowManager();
            //将DecorView添加到Window中
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
    ...
}

    继续看WindowManagerImpl的addView方法:

package android.view;
public final class WindowManagerImpl implements WindowManager {
    ...
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //调用的是WindowManagerGlobal对象的addView方法,
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    ...
}

    由上述addView方法,可知WindowManager也没有具体实现addView的方法,而是再次调用了WindowManagerGlobal对象的addView方法。好吧,那就继续看WindowManagerGlobal对象的addView方法:

package android.view;
public final class WindowManagerGlobal {
    ...
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //下面3个if是验证非空以及类型
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        //设置params相关
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            //调整窗口布局
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // 系统属性的监听
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            //好像是预防某种关闭没彻底
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            //创建当前DecorView对象的ViewRootImpl对象
            root = new ViewRootImpl(view.getContext(), display);
            //把经过处理后的params设置给DecorView
            view.setLayoutParams(wparams);
            
            //存储当前应用进程的所有DecorView、ViewRootImpl、params
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            //进程间通信,真正地显示在Display上
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }
    ...
}

    WindowManagerGlobal是管理app进程中所有的窗口的,相关的DecorView、ViewRootImpl、WindowManager.LayoutParams会存储到WindowManagerGlobal中的相关成员变量中进行管理

private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();

    代码确实有点儿多,下面setView方法只关注两个点:

package android.view;
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
    ...
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ...
        //这里会走View的绘制流程
        requestLayout();
        ...
        //这里利用Binder机制与WindowManagerService跨进程通信,真正地显示在屏幕上
        es = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
        ...
    }
    ...
}

总结

    整个流程涉及到的源码以及细节都太多太多,后续随着对Window机制了解的深入,会逐渐完善这篇博客。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容