4.1 初始ViewRoot和DecorView

1.一切从setContentView说起以下源码均取自Android API 23。

public class ViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view);
    }
}

AppCompatActivity中

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback{
    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }
}

AppCompatDelegate中

public abstract class AppCompatDelegate {
    public abstract void setContentView(@LayoutRes int resId);
}

其实现AppCompatDelegateImplV7:

class AppCompatDelegateImplV7 extends AppCompatDelegateImplBase{.
    private ViewGroup mSubDecor;
    @Override
    public void setContentView(int resId) {
        ensureSubDecor();
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        LayoutInflater.from(mContext).inflate(resId, contentParent);
        mOriginalWindowCallback.onContentChanged();
    }
}
// AppCompatDelegateImplBase继承自AppCompatDelegate
abstract class AppCompatDelegateImplBase extends AppCompatDelegate

上面的代码除了第一行外,都很好理解。mSubDecor拿到contentParent,并把传入的resId以子View的形式添加到contentParent。可见contentparent是我们布局文件的父View,也是decor的子View。而第一行代码就是初始化mSubDecor.

private void ensureSubDecor() {
    if (!mSubDecorInstalled) {
        mSubDecor = createSubDecor();
        ...
    }
}
private ViewGroup createSubDecor() {
    
    mWindow.getDecorView();

    final LayoutInflater inflater = LayoutInflater.from(mContext);
    ViewGroup subDecor = null;

    if (!mWindowNoTitle) {
        if (mIsFloating) {
            subDecor = (ViewGroup) inflater.inflate(
                    R.layout.xxx, null);
            mHasActionBar = mOverlayActionBar = false;
        } else if (mHasActionBar) {
            subDecor = (ViewGroup) LayoutInflater.from(themedContext)
                    .inflate(R.layout.xxx, null);
        }
    } else {
        subDecor = (ViewGroup) inflater.inflate(
                    R.layout.xxx, null);
    }

    mWindow.setContentView(subDecor);

    return subDecor;
}

PhoneWindow是Window的实现类,看里面的上文出现的两个方法

@Override
public final View getDecorView() {
    if (mDecor == null) {
        installDecor();
    }
    return mDecor;
}
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();
    }
}        
protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}
@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    mLayoutInflater.inflate(layoutResID, mContentParent);
}

到这里为止,我们的布局文件已经加载到了Window中。下面看布局文件如何显示。

2. ViewRootImpl

先了解Activity的创建过程。我们知道java程序的执行是从main方法开始的,而Activity的main方法在ActivityThread中,Activity的生命周期也是在这里完成的。其他的先不多讲,先看Activity的启动方法

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);
    }
}    
final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
   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);
        }
    } 
}    

看ViewManager的addView方法

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

WindowManager继承ViewManager,也是接口。其实现类WindowManagerImpl

public final class WindowManagerImpl implements WindowManager{
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
}

Global的addVeiw方法

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);

    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
}

最终ViewRootImpl把WindowManager和DecorView连在一起。

3. ViewRootImpl

ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成的。在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联。

View的绘制流程是从ViewRoot的performTraversals方法开始的,它经过measure、layout、draw三个过程才能最终将一个View绘制出来。其中measure测量View的宽高,layout确定View在父容器中放置的位置,而draw负责将View绘制在屏幕上。

performTraversals会依此调用performMeasure、performLayout和performDraw三个方法,这三个方法分别完成顶级View的measure、layout、draw三大流程。其中performMeasure会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容器传递到了子元素中,这样就完成了一次measure过程。performLayout和performDraw的流程类似,唯一不同的是performDraw的传递过程是dispatchDraw来实现的。

4. setContentView

我们知道我们的布局文件和DecorView之间有一个ContentView。这个ContentView的id是android.R.content。所以是setContentView,而不是setView().

你可能感兴趣的:(4.1 初始ViewRoot和DecorView)