Activity和Window的关联

每个Activity都对应一个Window,具体是对应一个PhoneWindow。PhoneWindow不是一个视图,而是有一个DecorView,这是一个FrameLayout的派生类,他是Activity所对应的窗口中最顶级的视图,可以通过Window的getDecorView函数来获取最顶级的视图,这个函数内部会自动创建一个DecorView对象,使用DecorView的原因是Activity的窗口可以有一个有标题栏或者没有标题栏的视图,而内容视图是必须要的,在Activity中设置内容视图的方法是通过setContentView来实现的,而设置的contentView是DecorView的容器部分mContentParent的子视图,也就是DecorView是由标题栏部分和内容部分(mContentParent, id为:android.R.id.content,mContentParent 也是PhoneWindow的成员)组成,标题部分是可以设置Activity的某些特性来实现,而内容部分则需要用户去指定。也就是设置Activity的某些特性比如透明啊等都是对DecorView来设置的。


在Activity中有一个onContentChange的函数,主要的作用是当Activity的内容视图的父视图内的子视图有变换时(setContentView, addContentView时会调用上面的函数)




这里涉及窗口风格的概念,后续再补充。可以详细研究函数:


 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 < com.android.internal.R.styleable.Window.length; i++) {

                s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="

                        + a.getString(i);

            }

            System.out.println(s);

        }


        mIsFloating = a.getBoolean(com.android.internal.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(com.android.internal.R.styleable.Window_windowNoTitle, false)) {

            requestFeature(FEATURE_NO_TITLE);

        }


        if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {

            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));

        }


        WindowManager.LayoutParams params = getAttributes();


        if (!hasSoftInputMode()) {

            params.softInputMode = a.getInt(

                    com.android.internal.R.styleable.Window_windowSoftInputMode,

                    params.softInputMode);

        }


        if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,

                mIsFloating)) {

            /* All dialogs should have the window dimmed */

            if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {

                params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;

            }

            params.dimAmount = a.getFloat(

                    android.R.styleable.Window_backgroundDimAmount, 0.5f);

        }


        if (params.windowAnimations == 0) {

            params.windowAnimations = a.getResourceId(

                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);

        }


        // The rest are only done if this window is not embedded; otherwise,

        // the values are inherited from our container.

        if (getContainer() == null) {

            if (mBackgroundDrawable == null) {

                if (mBackgroundResource == 0) {

                    mBackgroundResource = a.getResourceId(

                            com.android.internal.R.styleable.Window_windowBackground, 0);

                }

                if (mFrameResource == 0) {

                    mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);

                }

                if (false) {

                    System.out.println("Background: "

                            + Integer.toHexString(mBackgroundResource) + " Frame: "

                            + Integer.toHexString(mFrameResource));

                }

            }

            mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);

        }


        // Inflate the window decor.


        int layoutResource;

        int features = getLocalFeatures();

        // System.out.println("Features: 0x" + Integer.toHexString(features));

        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {

            if (mIsFloating) {

                layoutResource = com.android.internal.R.layout.dialog_title_icons;

            } else {

                layoutResource = com.android.internal.R.layout.screen_title_icons;

            }

            // System.out.println("Title Icons!");

        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {

            // Special case for a window with only a progress bar (and title).

            // XXX Need to have a no-title version of embedded windows.

            layoutResource = com.android.internal.R.layout.screen_progress;

            // System.out.println("Progress!");

        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {

            // Special case for a window with a custom title.

            // If the window is floating, we need a dialog layout

            if (mIsFloating) {

                layoutResource = com.android.internal.R.layout.dialog_custom_title;

            } else {

                layoutResource = com.android.internal.R.layout.screen_custom_title;

            }

        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {

            // If no other features and not embedded, only need a title.

            // If the window is floating, we need a dialog layout

            if (mIsFloating) {

                layoutResource = com.android.internal.R.layout.dialog_title;

            } else {

                layoutResource = com.android.internal.R.layout.screen_title;

            }

            // System.out.println("Title!");

        } else {

            // Embedded, so no decoration is needed.

            layoutResource = com.android.internal.R.layout.screen_simple;

            // System.out.println("Simple!");

        }


        mDecor.startChanging();


        View in = mLayoutInflater.inflate(layoutResource, null);

        decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT));


        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

        if (contentParent == null) {

            throw new RuntimeException("Window couldn't find content container view");

        }


        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {

            ProgressBar progress = getCircularProgressBar(false);

            if (progress != null) {

                progress.setIndeterminate(true);

            }

        }


        // Remaining setup -- of background and title -- that only applies

        // to top-level windows.

        if (getContainer() == null) {

            Drawable drawable = mBackgroundDrawable;

            if (mBackgroundResource != 0) {

                drawable = getContext().getResources().getDrawable(mBackgroundResource);

            }

            mDecor.setWindowBackground(drawable);

            drawable = null;

            if (mFrameResource != 0) {

                drawable = getContext().getResources().getDrawable(mFrameResource);

            }

            mDecor.setWindowFrame(drawable);


            // System.out.println("Text=" + Integer.toHexString(mTextColor) +

            // " Sel=" + Integer.toHexString(mTextSelectedColor) +

            // " Title=" + Integer.toHexString(mTitleColor));


            if (mTitleColor == 0) {

                mTitleColor = mTextColor;

            }


            if (mTitle != null) {

                setTitle(mTitle);

            }

            setTitleColor(mTitleColor);

        }


        mDecor.finishChanging();


        return contentParent;

    }




那么Window和WindowManager的关系如何呢?


在Activity的attach函数内部会为每个Activityi创建一个唯一对应的PhoneWindow对象,同时会为每个Activity创建一个WindowManager对象,代码如下:

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

       

 mWindowManager = mWindow.getWindowManager();



系统有一个全局的WindowManager对象(WindowManagerImpl的实例),

而每个Window内部会创建一个LocalWindowManager(也实现了WindowManager,但构造函数是接收一个WindowManagerImpl对象,并且把所有调用直接转到WindowManagerImpl中),所以虽然每个Activity都对应一个唯一的WindowManager对象,但其实内部总是只有一个WindowManager对象(单例对象)。



WindowManager和Window和Activity之间的关系如何??


在系统启动一个Activity时也就是ActivityThread调用handleLaunchActivity时内部会调用activity的WindowManager的addView方法,把decorView和一个新的ViewRoot来建立关系,见下面!!!



WindowManager管理着Window中的decorView和一个ViewRoot的对应关系(会创建一个ViewRoot对象来跟decorView建立关系),每个decorView都会对应一个ViewRoot对象,并且ViewRoot对象会持有一个对decorView的引用,ViewRoot是一个Handler的派生类,在ViewRoot中会重载handleMessage。



ViewRoot在创建的时候会创建一个W类型的对象mWindow,


 这个W是一个IWindow.Stub的派生类。


系统会创建一个IWindowSession的全局对象sWindowSession


ViewRoot在跟decorView绑定时是调用setView方法,
这个方法内部将ViewRoot内的W注册到sWindowSession中去。

sWindowSession.add(mWindow,….),这里的W是一个存根。

注册后会再WindowManagerService中建立代理,当用户手势触摸发生时,是WindowManagerService截获的,然后通过代理经过RPC传递到对应的存根来,
也就是ViewRoot的W中,在W的onTrasncat中向ViewRoot调用sendMessage把触摸消息发送到主线程的RunLooper中。

ViewRoot的handleMessage中对触摸处理如下:

调用绑定的PhoneWindow.decorView的

public boolean dispatchTouchEvent(MotionEvent ev) {

            final Callback cb = getCallback();

            return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super

                    .dispatchTouchEvent(ev);

        }

   
这里给PhoneWindow对应的cb也就是Activity一次捕获触摸处理的机会。
如果Activity不处理则由视图递归进行处理。











Activity中有ActivityGroup,同样Window也有 void  setContainer(Window container)来设置容器窗口跟Activity的层次结构对应,而这种层次关系是在Activity创建时建立Activity和Window的关系以及层次关系的。

你可能感兴趣的:(window,Activity)