干就完事了 setContentView()探秘一

来源:互联网 发布:js bind()方法 编辑:程序博客网 时间:2024/04/27 21:42

1、源头 Activity的setContentView()


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

mWindow其实就是一个PhoneWindow在Activity的attach方法里面 Policy.makeNewWindow

2、PhoneWindow
public void setContentView(int layoutResID) {
      installDecor();   
      mLayoutInflater.inflate(layoutResID, mContentParent);
}

mLayoutInflater.inflate(layoutResID, mContentParent) ---Activity中setContentView(),其实主要就是mContentParent.addView(view),mContentParent是ViewGroup


3、ViewGroup

public void addView(View child, int index, LayoutParams params) {
    requestLayout();//重点关注啊
    invalidate(true);
    addViewInner(child, index, params, false);
}


4、View的requestLayout()
public void requestLayout() {
    mParent.requestLayout();
}

重点是mParent.requestLayout(),调用会向上递归回到PhoneWindow里的mContentParent


mContentParent = generateLayout(mDecor);

protected ViewGroup generateLayout(DecorView decor) {
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    return contentParent ;
}

继续追下去findViewById()

public View findViewById(@IdRes int id) {
    return getDecorView().findViewById(id);
}

哇原来如此啊 mContentParent的parent就是我们常在Activity里写的getWindow().getDecorView()
再看decor的parent是什么,Activity里面


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

追下去wm.addView(),Window类里面

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

public WindowManager getWindowManager() {
    return mWindowManager;
}

追下去 WindowManagerImpl

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

mGlobal就是WindowManagerGlobal

public void addView(View view, ViewGroup.LayoutParams params,
    //...
    ViewRootImpl root;
    //...
    root = new ViewRootImpl(view.getContext(), display);
    //...
    root.setView(view, wparams, panelParentView);
    //...
    
}

追下去root.setView(),ViewRootImpl类里面

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    //...
    view.assignParent(this);
    //...
}

assignParent()设置View的mParent,得知DecorView的parent就是ViewRootImpl

5、ViewRootImpl

requestLayout(){

  mChoreographer.postCallback(
       
Choreographer.CALLBACK_TRAVERSAL,mTraversalRunnable, null);

}

mTraversalRunnable.run(){

  doTraversal(){

  performTraversals(){

  performMeasure();

  performLayout();

  performDraw();

  }

  }

}

基本逻辑:
ViewGroup.addView(view)会调用requestLayout()
View.requestLyaout()每次都会递归回到Activity最上层的那个DecorView的parent就是ViewRootImpl
然后ViewRootImpl开始执行measure()、layout()、draw(),这几个方法里面会再递归遍历执行child View的measure()、layout()、draw()






原创粉丝点击