Activity的View构建过程

来源:互联网 发布:厨房专用垃圾桶淘宝 编辑:程序博客网 时间:2024/05/19 14:35

Activity关联到当前App时,会构建属于自己的Window对象,并且注册事件的监听。

 mWindow = PolicyManager.makeNewWindow(this);

mWindow.setCallback(this);

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

在手机平台上,Window对象就是PhoneWindow的实例,这是Activity View的容器。

 

一般在App中,都是在Activity启动时调用setContentView设置整个Activity的布局。

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

 

而在setContentView中,则是利用PhoneWindow去实现布局的构造。

    getWindow().setContentView(layoutResID);

 

PhoneWindow.java

    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
}

 

这里首先创建DecorView,这个DecorView是Activity中所有View 的根。创建DecorView后根据设定的Activity的theme或是属性,从系统预定义的布局中选择一个创建Content并加入DecorView,同时返回其中ID_ANDROID_CONTENT的ViewGroup(就是说这些布局都有相同ID的ViewGroup),作为用户自定义布局的根容器。最后将用户的布局infalte后加入到该容器中。

 

但是这里需要注意的是,setContentView创建这些布局结构后,并没有立即跟系统的事件系统接上,也没有加入到系统的WindowManager的管理中。这些关键步骤,必须等到特定的时机才会执行。这个时机,就是onResume被回调之前,ActivityThread处理Activity从onCreate->onResume的转换时。

ActivityThread.java

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
    ActivityRecord r = performResumeActivity(token, clearHide);
    // If the window hasn't yet been added to the window manager,
    // and this guy didn't finish itself or start another activity,
    // then go ahead and add the window.

    boolean willBeVisible = !a.mStartedActivity;
    if (!willBeVisible) {
        try {
            willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                            a.getActivityToken());
        } catch (RemoteException e) {
        }
    }


    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();

        //这里将之前setContentView时构建的DecorView传给Activity
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (a.mVisibleFromClient) {
           a.mWindowAdded = true;

           //将DecorView注册给WindowManager
           wm.addView(decor, l);
        }
    }

}

 

DecorView注册给WindowManager,WindowManger构建一个对应的ViewRoot。ViewRoot是Activity与WindowManagerService之间的桥梁,Activity通过ViewRoot告诉WindowManagerService将自己显示出来,通过ViewRoot收到WindowManagerService分发来的系统事件(Touch、Key....)。

WindowManagerImpl.java

private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
{

   .....

   root = new ViewRoot(view.getContext());

   mViews[index] = view;
   mRoots[index] = root;

   // 这里最关键,DecorView注册给ViewRoot,建立父子关系

   root.setView(view, wparams, panelParentView);

}

 

到此,Activity的布局就算找到组织了,以后显示,刷新,事件都由ViewRoot管理了。