Window Activity View ViewRootImpl

Window is an abstract class, and its only implementation class is PhoneWindow. PhoneWindow is created in the attch method of the 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) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        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); } mWindowManager = mWindow.getWindowManager(); }Copy the code

So each activity has a PhoneWindow and an mWindowManager

(WindowManager is an interface that inherits ViewManager, with addView, updateViewLayout, and removeView methods. The implementation class of WindowManager is WindowManagerImpl. In WindowManagerImpl, the implementation of these three methods is implemented by Windows ManagerGlobal.

The window setContentView method is called when setting the layout of the Activity using the setContentView method of the Activity. In this method, the DecorView is generated and bound to the current window

 private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if(! mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures ! = 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); }}else {
            mDecor.setWindow(this);
        }
        if(mContentParent == null) { mContentParent = generateLayout(mDecor); / / 1Copy the code

Notice the code at 1, which generates the mContentParent. If we go to generateLayout, which generates the mContentParent, we’ll see that if we set the activity’s subject information here, So that’s why you set the theme before setContentView, right

protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.

        TypedArray a = getWindowStyle();

        if (false) {
            System.out.println("From style:");
            String s = "Attrs:";
            for (int i = 0; i < R.styleable.Window.length; i++) {
                s = s + "" + Integer.toHexString(R.styleable.Window[i]) + "="
                        + a.getString(i);
            }
            System.out.println(s);
        }

        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
        if (mIsFloating) {
            setLayout(WRAP_CONTENT, WRAP_CONTENT);
            setFlags(0, flagsToUpdate);
        } else {
            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
        }

        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
            requestFeature(FEATURE_ACTION_BAR);
        }

    .....
    
       ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//1

Copy the code

The code at 1 finds that the mContentParent is generated by findViewById(ID_ANDROID_CONTENT), where ID_ANDROID_CONTENT is Android.r.D.C. Tent, which is the layout below the notification bar, The DecorView is then the following layout of the activity.

Display the layout in onResume via WindowManager.addView(decor).

Now let’s look at the WindowManager addView method

The implementation class of WindowManager as analyzed above is WindowManagerImpl, and WindowManagerImpl implements view addition internally through Windows ManagerGlobal.

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        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");
        }

        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) { // Start watchingfor system property changes.
            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); } root = new ViewRootImpl(view.getContext(), display); //1 view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } / /dothis last because it fires off messages to start doing things try { root.setView(view, wparams, panelParentView); //2 } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. synchronized (mLock) { final int index = findViewLocked(view,false);
                if (index >= 0) {
                    removeViewLocked(index, true); } } throw e; }}Copy the code

Can see created ViewRootImpl in 1 place, WindowManagerGlobal internal maintenance for three array is used to store add view, ViewRootImpl, WindowManager. LayoutParams and going to remove the view.

 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>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();
Copy the code

Finally, root.setView(View, wParams, panelParentView) is called in code 2, and requestLayout is called inside the method to execute the view’s three processes. The Window addition request is then sent to WindowManagerService through the Binder object WindowSession.

Summary: Each Activity corresponds to a PhoneWindow, which is associated with a decorView. To set up the layout, use WindowManager addView. Each call to addView creates a ViewRootImpl, which creates a view tree.