Window

Window是管理view的一个类,Window本身是不存在的。一个页面就是一个Window才管理。
所以View的机制里面也讲到Window的方法。

Activity的Window的创建

在Activity启动的最后一步,进入ActivityThread,会通过类加载的方式创建Activity,然后在attch的过程中,创建Window,并且把contentView设置上去。

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, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
       ...
    }

下面就是设置contentView的code。

    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

在ActivityThread的handleResumeActivity方法中,这个是Activity启动过程的一步,前面文章已经讲述。

    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

这里创建的DecorView,这样我们每个Activity的view的层次结构就清晰了
phonewindow》DecorView》layoutView
每个层级都包含下个层级。这里phonewindow只是逻辑上的概念,实际显示不存在。

Dialog的Window

Dialog的Window跟Activity是类似的。

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == ResourceId.ID_NULL) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    final Window w = new PhoneWindow(mContext);
       ...
    }

可以看到也是PhoneWindow
所以普通Dialog必须使用Activity的context,是应为token导致,applicaiton是没有当前token的。
系统的Window就不需要Activity的context。比如Toast

Toast的Window

Toast是系统级的window,所以这个window是系统创建的,不需要activity的context,也跟docerView没有关系。
下面是toast经过IPC以后调用的地方,but,没有地方发现那个window!!!

public void handleShow() {

        if (mView != mNextView) { //1.判断下一个toast的view 和当前显示的是否不同.不同的话,移除现在的,显示下一个.
            // remove the old view if necessary
            handleHide(); //2.移除当前窗口
            mView = mNextView;
            Context context = mView.getContext().getApplicationContext()//3.得到context和包名
            String packageName = mView.getContext().getOpPackageName();
            if (context == null) {
                context = mView.getContext();
            }
              //3.得到wms
            mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
            if (mView.getParent() != null) { //4.如果他的父节点不为空,则需要先删除它在添加.不然会报错
                mWM.removeView(mView);
            }      
            mWM.addView(mView, mParams);
        }
    }


mWM.addView(mView, mParams);的window用的是那个,从图看,用的是当前页面的。
然后我们回到home页面,在看看。
初步分析下来,toast的是由全局windowmanager管理的,至于是那个window,看下来是当前window。这块存疑

发表评论

电子邮件地址不会被公开。 必填项已用*标注