zoukankan      html  css  js  c++  java
  • android Window(一)从setConetView说起

    Activity的源码

    首先从setContentView这里调用的mWindow的 setConetView()

    private Window mWindow;
    public void setContentView(View view) {
            getWindow().setContentView(view);
            initWindowDecorActionBar();
        }
    
    public Window getWindow() {
        return mWindow;
    }

     那么这mWindow什么时候初始化?

    final void attach(...) {
            attachBaseContext(context);
            mFragments.attachHost(null /*parent*/);
            mWindow = new PhoneWindow(this, window, activityConfigCallback);
            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);
            }
            //...
            //给window设置windowManger
            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());
            }
            mWindowManager = mWindow.getWindowManager();
            mCurrentConfig = config;
    
            mWindow.setColorMode(info.colorMode);
        }

    可以看到这个mWindow 其实是一个PhoneWindow的实例,那么phoneWindow干了什么

    可以查看PhoneWindow的源码

    152    // This is the view in which the window contents are placed. It is either
    153    // mDecor itself, or a child of mDecor where the contents go.
    154    private ViewGroup mContentParent;
    
    390    @Override
    391    public void setContentView(View view, ViewGroup.LayoutParams params) {
    392        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    393        // decor, when theme attributes and the like are crystalized. Do not check the feature
    394        // before this happens.
    395        if (mContentParent == null) {
    396            installDecor();
    397        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
    398            mContentParent.removeAllViews();
    399        }
    400
    401        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
    402            view.setLayoutParams(params);
    403            final Scene newScene = new Scene(mContentParent, view);
    404            transitionTo(newScene);
    405        } else {
    406            mContentParent.addView(view, params);
    407        }
    408        final Callback cb = getCallback();
    409        if (cb != null && !isDestroyed()) {
    410            cb.onContentChanged();
    411        }
    412    }

    这里setContentView 主要是 先判断mContentParent是否初始化如果没有初始化调用installDecor 。然后将view添加到mContentParent的ViewGroup中

    那么  installDecor  做了些什么

            private DecorView mDecor;
    3551    private void installDecor() {
    3552        if (mDecor == null) {
    3553            mDecor = generateDecor();
    3554            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
    3555            mDecor.setIsRootNamespace(true);
    3556            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
    3557                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
    3558            }
    3559        }
    3560        if (mContentParent == null) {
    3561            mContentParent = generateLayout(mDecor);
    3562
    3563            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
    3564            mDecor.makeOptionalFitsSystemWindows();
    3565
    3566            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
    3567                    R.id.decor_content_parent);
    3568
    3569            if (decorContentParent != null) {
    3570                mDecorContentParent = decorContentParent;
    3571                mDecorContentParent.setWindowCallback(getCallback());
    3572                if (mDecorContentParent.getTitle() == null) {
    3573                    mDecorContentParent.setWindowTitle(mTitle);
    3574                }
    3575
    3576                final int localFeatures = getLocalFeatures();
    3577                for (int i = 0; i < FEATURE_MAX; i++) {
    3578                    if ((localFeatures & (1 << i)) != 0) {
    3579                        mDecorContentParent.initFeature(i);
    3580                    }
    3581                }
    
    3582
    3583                mDecorContentParent.setUiOptions(mUiOptions);
    3584
                //setIcon,setLogo ...
    3608            } else {
                //setTitle ...3627        
                 }
                 //...       
                 }
    3686    }

     installDecor 主要干两件事情

    1. 如果mDecor没有初始化generateDecor()初始化
    2. 如果mContentParent 没有初始化generateLayout()初始化

    generateDecor 就是返回一个新的DecorView

    3199    protected DecorView generateDecor() {
    3200        return new DecorView(getContext(), -1);
    3201    }
    
    
    这里实例化了DecorView,而DecorView则是PhoneWindow类的一个内部类,继承于FrameLayout,由此可知它也是一个ViewGroup。 
    那么DecroView到底充当了什么样的角色呢? 
    其实,DecorView是整个ViewTree的最顶层View,它是一个FrameLayout布局,代表了整个应用的界面。在该布局下面,有标题view和内容view这两个子元素,而内容view则是上面提到的mContentParent

    DecorView
     private final class DecorView extends FrameLayout implements RootViewSurfaceTaker{
    //...
    }

    generateLayout()
    给activity的根布设置各种属性
    protected ViewGroup generateLayout(DecorView decor) {
            // Apply data from current theme.
            // 从主题文件中获取样式信息
            TypedArray a = getWindowStyle();
    
            //...
    
            if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
                requestFeature(FEATURE_NO_TITLE);
            } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
                // Don't allow an action bar if there is no title.
                requestFeature(FEATURE_ACTION_BAR);
            }
    
            if(...){
                ...
            }
    
            // Inflate the window decor.
            // 加载窗口布局
            int layoutResource;
            int features = getLocalFeatures();
            // System.out.println("Features: 0x" + Integer.toHexString(features));
            if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
                layoutResource = R.layout.screen_swipe_dismiss;
            } else if(...){
                ...
            }
    
            View in = mLayoutInflater.inflate(layoutResource, null);    //加载layoutResource
            decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); //往DecorView中添加子View,即mContentParent
            mContentRoot = (ViewGroup) in;
    
            ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); // 这里获取的就是mContentParent
            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);
                }
            }
    
            if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
                registerSwipeCallbacks();
            }
    
            // Remaining setup -- of background and title -- that only applies
            // to top-level windows.
            //...
    
            return contentParent;
        }

    根据设置的主题样式来设置DecorView的风格,比如说有没有titlebar之类的,接着为DecorView添加子View,而这里的子View则是上面提到的mContentParent,如果上面设置了FEATURE_NO_ACTIONBAR,那么DecorView就只有mContentParent一个子View,所以mContentParent是DecorView本身或者是DecorView的一个子元素。 

    用一幅图来表示DecorView的结构如下:

    小结:DecorView是顶级View,内部有titlebar和contentParent两个子元素,contentParent的id是content,而我们设置的main.xml布局则是contentParent里面的一个子元素。

    setConetViewz就是把view 添加到顶层的DecorView里面的contentParent里面

    将DecorView添加至Window

    每一个Activity组件都有一个关联的Window对象,用来描述一个应用程序窗口。每一个应用程序窗口内部又包含有一个View对象,用来描述应用程序窗口的视图。上文分析了创建DecorView的过程,现在则要把DecorView添加到Window对象中。而要了解这个过程,我们首先要简单先了解一下Activity的创建过程: 
    首先,在ActivityThread#handleLaunchActivity中启动Activity,在这里面会调用到Activity#onCreate方法,从而完成上面所述的DecorView创建动作,当onCreate()方法执行完毕,在handleLaunchActivity方法会继续调用到ActivityThread#handleResumeActivity方法,我们看看这个方法的源码:

    ActivityThread.java

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { 
        //...
        ActivityClientRecord r = performResumeActivity(token, clearHide); // 这里会调用到onResume()方法
    
        if (r != null) {
            final Activity a = r.activity;
    
            //...
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow(); // 获得window对象
                View decor = r.window.getDecorView(); // 获得DecorView对象
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager(); // 获得windowManager对象
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l); // 调用addView方法
                }
                //...
            }
        }
    }
     
  • 相关阅读:
    试题 E: 迷宫
    对拍程序
    人群中钻出个光头
    HDU-魔咒词典(字符串hash)
    第八集 你明明自己也生病了,却还是要陪着我
    智力问答 50倒计时
    数据结构
    LeetCode刷题 fIRST MISSING POSITIVE
    LeetCode Best to buy and sell stock
    LeetCode Rotatelmage
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/9140366.html
Copyright © 2011-2022 走看看