View、Activity、Window、WindowManager之间的关系

Activity

Activity是Android系统中的四大组件之一, 是存放View对象的容器,是界面的载体,通过调SetContentView()方法显示View。
view

view是视图对象,是用户界面控件的基础,所有控件的顶层父类

Window

Window是一个抽象类,具体实现类是PhoneWindow。andorid中所有的视图都是依赖于Window来呈现,包括dialog、activity、toast。

Window根据z-ordered分类,根据区间不同,可分三种类型,应用类Window、子Window、系统Window,层级大的会覆盖在层级小的Window的上面应用类的Window的层级范围是1-99,常见的有toast和系统状态栏,子Window的层级范围是1000-1999,他们不能单独存在,需要依附于父Window,常见的有dialog,系统Window的层级的范围是2000-2999,常见的有activity。

WindowManager

WindowManager是外界访问Window的入口,通过WindowManager可以创建Window,但Window的具体实现在WindowManagerService中,WindowManager和WindowManagerService的交互式一个IPC过程。

WindowManager是一个接口,它的实现类是WindowManagerImpl类,WindowManagerImpl内部实现WindowManager的addView、updateViewLayout、removeView方法对Window进行添加、删除、修改,但WindowManagerImpl不是直接实现,而是交给WindowManagerGlobal的工厂实例来处理。

@Override
public void addView(View view,ViewGroup.LayoutParams params){
  mGlobal.addView(view,params,mDisplay,mParentWindow);
}

@Override
public void updateViewLayout(View view,ViewGroup.LayoutParams params){
  mGlobal.updateViewLayout(view,params);
}

@Override
public void removeView(View view){
  mGlobal.removeView(view,false);
}

View、Activity、Window之间的关系

一句话概括三者的关系

 Activity就像是一扇贴着窗花的窗口,Window就想上窗口上面的玻璃,而View对象就像一个个贴在玻璃上的窗花。

首先,我们通过LayoutInflater加载xml布局或实例化View得到view对象,activity通过调用setContentView()方法将view暂时在activity上,而activity在调用setContentView()时实际上是调用了Window的setContentView()方法,view是通过activity呈现在Window上

/** 
  * Set the activity content from a layout resource.  The resource will be 
  * inflated, adding all top-level views to the activity. 
  * 
  * @param layoutResID Resource ID to be inflated. 
  * 
  * @see #setContentView(android.view.View) 
  * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) 
  */  
 public void setContentView(@LayoutRes int layoutResID) {  
     getWindow().setContentView(layoutResID);  
     initWindowDecorActionBar();  
 } 


getWindow()方法获取Window实例,即PhoneWindow实例,PhoneWindow实例是在activity的attach()中被赋值

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) {  
        ...
        mWindow = new PhoneWindow(this);  
        mWindow.setCallback(this);  
        mWindow.setOnWindowDismissedCallback(this);  
        mWindow.getLayoutInflater().setPrivateFactory(this);  
        ...
        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;  
    } 

前面已经说到,最终的view是通过PhoneWindow的setContentView()方法添加到Window上,那让我们看一下PhoneWindow的setContentView()的具体实现

@Override  
// This is the top-level view of the window, containing the window decor.  
   private DecorView mDecor;  
  
    // This is the view in which the window contents are placed. It is either  
    // mDecor itself, or a child of mDecor where the contents go.  
private ViewGroup mContentParent; 
@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.  
        if (mContentParent == null) {  
            installDecor();  
       } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  
           mContentParent.removeAllViews();  
        }  
  
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,  
                    getContext());  
            transitionTo(newScene);  
       } else {  
           mLayoutInflater.inflate(layoutResID, mContentParent);  
       }  
      final Callback cb = getCallback();  
        if (cb != null && !isDestroyed()) {  
            cb.onContentChanged();  
        }  
    } 

mContentParent是一个ViewGroup,用来存放通过setContentView获取到的view。而installDecor()方法的作用是初始化DecorView对象,那DecorView对象又是什么呢?其实DecorView对象是Activity的根布局文件,它包含mContentParent的同时还包含了titlebar。

那么总结起来就是,activity的setContentView()方法,最终会把view添加到DecorView上,而DecorView的载体是PhoneWindow对象,PhoneWindow通过WindowManager操作view,包括增删改,实际的执行者是WindowManagerGlobal。

那么还有一个疑问,就是上面的setContentView()方法中并没有看到WindowManager的具体操作啊?

其实答案是这样的,setContentView()方法执行完毕,这个时候界面还没有显示出任何东西来,而仅仅是将mDecor->mContentParent->(customer layout)一个这样的树状结构给搭建好了而已,setContentView()方法是在activity启动方法performLaunchActivity()中执行的,在执行完performLaunchActivity()方法后,activity再会执行另一个方法,handleResumeActivity()方法,具体对view的增删改都是在此方法中执行。

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
        boolean reallyResume) {
    ...

    ActivityClientRecord r = performResumeActivity(token, clearHide);

    if (r != null) {
        final Activity a = r.activity;
        ...
        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 (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }
            ...
        }
    ...
    }
}

vm.addView()方法就是将view通过WindowManager添加到Window上的。

那么View、Activity、Window、WindowManager之间的关系就梳理到这儿了。

你可能感兴趣的:(android)