[Android-FrameWork]Android-PhoneWindow详细分析

我们都知道Activity的层有一个Window也有一个WindowManage其中对应如下

Activity所拥有的Window与 WindowManage

1.PhoneWindow
2.PhoneWindowManage

在刚开始我们设置的时候是这样设置的

  setContentView(R.layout.activity_main);

我们跟进一下

public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID); //主要看这个,我们先看看这个getWindow是什么
        initWindowDecorActionBar();//这个是DecorView初始化ActionBar的,
                                                      //DecorView为整个Activity也就是整个
                                                      //PhoneWindow底层的View
    }

我们先看看这个getWindow是什么

 public Window getWindow() {
        return mWindow; //直接return了一个mWindow
    }

//看一下这个mWindow是什么

  mWindow = new PhoneWindow(this, window, activityConfigCallback); //底层就是PhoneWindow

//再来看一下WindowManage

 mWindowManager = mWindow.getWindowManager();
//也就是说用的是PhoneWindow的WindowManager

我们继续跟进到PhoneWindow类里边

回到我们的setContentView



 /**
     * XINHAO_HAN  设置Activity的View
     * @param layoutResID
     */
    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.

        /**
         * 如果第一次设置  mContentParent为ViewGroup
         */
        if (mContentParent == null) {
            /**
             * 就开始初始化
             */
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            /**
             * 否则就移除掉所有子View等待重新添加
             */
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            //如果视图跟新就通知外部类
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

我们继续看一下 installDecor();

  private void installDecor() {
        mForceDecorInstall = false;
        //如果DecorView为空就开始设置DecorView
        if (mDecor == null) {
            //Decor就是在这里创建的,我们看一下这个方法
            mDecor = generateDecor(-1);
            //获取焦点
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }

    ......
}

我们看一下这个方法 generateDecor(-1);

protected DecorView generateDecor(int featureId) {
        // System process doesn't have application context and in that case we need to directly use
        // the context we have. Otherwise we want the application context, so we don't cling to the
        // activity.
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext().getResources());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        return new DecorView(context, featureId, this, getAttributes());
    }

这块是直接new了一个DecorView,就相当于要添加到PhoneWindow里边的View

   mEnterTransition = getTransition(mEnterTransition, null,
                        R.styleable.Window_windowEnterTransition);
                mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
                        R.styleable.Window_windowReturnTransition);
                mExitTransition = getTransition(mExitTransition, null,
                        R.styleable.Window_windowExitTransition);
                mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
                        R.styleable.Window_windowReenterTransition);
                mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
                        R.styleable.Window_windowSharedElementEnterTransition);
                mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
                        USE_DEFAULT_TRANSITION,
                        R.styleable.Window_windowSharedElementReturnTransition);
                mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
                        R.styleable.Window_windowSharedElementExitTransition);
                mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
                        USE_DEFAULT_TRANSITION,
                        R.styleable.Window_windowSharedElementReenterTransition);
                if (mAllowEnterTransitionOverlap == null) {
                    mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
                            R.styleable.Window_windowAllowEnterTransitionOverlap, true);
                }
                if (mAllowReturnTransitionOverlap == null) {
                    mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
                            R.styleable.Window_windowAllowReturnTransitionOverlap, true);
                }
                if (mBackgroundFadeDurationMillis < 0) {
                    mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
                            R.styleable.Window_windowTransitionBackgroundFadeDuration,
                            DEFAULT_BACKGROUND_FADE_DURATION_MS);
                }
                if (mSharedElementsUseOverlay == null) {
                    mSharedElementsUseOverlay = getWindowStyle().getBoolean(
                            R.styleable.Window_windowSharedElementsUseOverlay, true);
                }

//这块是设置了一些用户设置的主题什么的

然后感觉没了? 没了??不可能啊,它应该是有一个东西添加到WindowManager里边的,否则什么都不会显示

然后我在ActivityThread里边找到了它添加的一些方法

 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 (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        //重点在这里------------------------------------------------------------------------------------
                        wm.addView(decor, l);
                    } else {
                        // The activity will get a callback for this {@link LayoutParams} change
                        // earlier. However, at that time the decor will not be set (this is set
                        // in this method), so no action will be taken. This call ensures the
                        // callback occurs with the decor set.
                        a.onWindowAttributesChanged(l);
                    }
                }

我们可以看出在Activity相当于一个PhoneWindow一个维护类.

当所有东西都初始化好了(getDecorView和PhoneWindow)以后再ActivityThread中直接调用

知识点(总结)

1.Activity中的setContentView实际上是给Activity对应的Window设置
2.Activity对应的Window是PhoneWindow
3.Activity的根目录为DecorView,在 Android当中有一个实体id android.R.id.content
4.Activity添加布局是在ActivityThread中添加的,并且在PhoneWindow初始化好之后(DecorView)
5.DecorView的布局是集成于FramLayout,并且有统一的格式,包括我们看到的,状态栏,布局,TitleBar,
6.可以说是以外得把,你可以试试用Activity的WindowManager添加一个View,然后用getApplicationContext的WindowManager添加一个View然后对比效果
效果是如下的,Activity-WindowManager添加的View只能依附在于Activity上不能依附在所有APP上边,Activity销毁后可能会提示窗口泄露,没有移除掉,但是不会奔溃,只是提示,Activity-WindowManager所添加的View是根据Activity的生命周期而变化的(绑定在一起的),而getApplicationContext所添加的WindowManager的View是飘在整个系统上边的

另外还有一点,就是Dialog其实并不需要在Activity上弹出,这个大家可以参考一下,而且这个是有依据的,大家手机电量低于15%的时候,是不是不管你在那块都会给你弹出一个Dialog提示电量低于15%,请连接电源.这个是一个知识点奥.

有错误的地方欢迎大神指出来,大家共同进步 _

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值