Android View 工作原理

作者: liu_liu_ | 来源:发表于2017-02-20 09:56 被阅读116次

本文从Activity 创建view,到View的绘制全过程,最终呈现在Activity做一个比较全面的梳理。

1. View在Activity上创建

这里要提到有关Activiy、Window、WindowManager等的相关知识。
ActivityThread 的performLaunchActivity是启动一个Activity的入口,此方法会创建一个Activity。

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            //1. 通过反射创建一个acitiviy
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ...
        }

        try {
               ...
              //2. 创建window 对象
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
                ...
                //3. 调用ActivityOncreate方法
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
        return activity;
    }

在Activity的attach中创建相应的PhoneWindow对象,并设置回调(详见PhoneWindow中Callback接口),此时Activity持有该Window对象

  final void attach(Context context, ActivityThread aThread,
            Instrumentation instr,...) {
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
  }

当我们在Activity的setContentView方法调用了Window的setContentView ,

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

实际上调用了Window的setContentView

public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            //1. 构建Decor
            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 {
            // 2. 将布局inflate到mContentParent上
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            //3. 回调给Activity
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

mContentParent相当于是DecorView的一部分,用来绘制content的部分

 private void installDecor() {
      ...
      mContentParent = generateLayout(mDecor);
      ...
}
protected ViewGroup generateLayout(DecorView decor) {
      //其中ID_ANDROID_CONTENT 即com.android.internal.R.id.content
       ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
       return contentParent
}

至此View被添加到顶级View, DecorView上,并显示在Activity的Window上了。

在ActivityThread的handleResumeActivity接口里:

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;
               ...
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // ViewManager的实现ViewManagerImpl 调用WindowManagerGlobal(WindowManager的实现)将DecorView添加到
                    wm.addView(decor, l);
                }

WindowManagerGlobal的addview会

...
root = new ViewRootImpl(view.getContext(), display);
...
root.setView(view, wparams, panelParentView);

其实ViewRootImpl的mView就是顶级View:Decoview 。
至此View被添加DecorView上并进入绘制流程。

2. View的绘制流程

在调用ViewRootImpl的setView中会执行其requestLayout方法


    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
            }
            ...
            // Schedule the first layout -before- adding to the window
            // manager, to make sure we do the relayout before receiving
            // any other events from the system.
            //在添加到windowMaganer之前首次执行layout
            requestLayout();
        }
    }

requestLayout会依次调用scheduleTraversals->doTraversal->performTraversals并最终进入绘制流程。
performTraversals会依次调用performMeasure,performDraw, performLayout,并相应的执行mView(DecorView)的measure,draw, layout,
到此view的绘制告一段落了。后面会继续讲到一些view绘制的详细内容

相关文章

网友评论

    本文标题:Android View 工作原理

    本文链接:https://www.haomeiwen.com/subject/sjnrwttx.html