ViewRootImpl、WindowManager、Windo

2017-08-23  本文已影响80人  Galileo_404

App应用窗口由Activity加载,整个窗口创建和Activity启动关联在一起。

如图所示

视图创建和添加流程

从Activity启动说起

Activity启动方法在ActivityThread的performLaunchActivity方法中,保留主要方法调用

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ............
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //通过classloader 加载Activity类
            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) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                //构建activity内部环境
                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);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                //调用onCreate方法,里面调用setContentView
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
               ......................

        return activity;
    }

mInstrumentation.newActivity(..),通过ClassLoader实现Activity的实例化;
执行activity.attach(..)方法,里面构建activity实例所需要的内部变量,包括创建Window和设置WindowManger

Window(PhoneWindow)和WindowManger创建

    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) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        //创建PhoneWindow,用于视图加载
        mWindow = new PhoneWindow(this);
        //将window事件通过回调接口,传递到Activity来处理
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
       
        //设置WindowManger
        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;
    }

attach(..)方法中,通过实例化创建PhoneWindow实例,通过context.getSystemService()方法获取WindowManager,

DecorView 创建

到现在Window和WindowmWindowManger已经创建好了,Window创建好,需要添加视图View,所有视图的根视图是DecorView,DecorView的创建在 setContent方法中。
上面说到创建Activity实例,调用attch方法,接下来就是调用mInstrumentation.callActivityOnCreate(..)方法,后面会调用Activity.onCreate()方法,在onCreate()方法中,通过setContentView()方法设置整个APP视图。

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

setContent最终调用的是PhoneWindow的setContentView方法,

    public void setContentView(int layoutResID) {
        
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
        ................
    }

installDecor()方法调用generateDecor()方法来创建DecorView,DecorView是所有布局的根布局。
WindowManger何时会将Window添加进来,阅读后面代码会发现当Activity执行OnResume时添加,添加时还会创建一个ViewRootImpl实例

ViewRootImpl创建

当ActivityThread执行handleResumeActivity方法时,里面会执行r.activity.makeVisible()方法

    void makeVisible() {
        if (!mWindowAdded) {
            //将DecorView添加到WindowManager
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

addView在WindowManagerImpl实现中调用WindowManagerGlobal的addView方法

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

            view.setLayoutParams(wparams);

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

        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

到此DecorView展示出来,显示在屏幕中,wm.addView(...)创建了ViewRootImpl,ViewRootImpl负责绘制各个子view

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
             .........
              requestLayout();

              .................
            //通过IPC,添加window交给WindowMangerServer
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
             .........
          }
}

mWindowSession类型是IWindowSession,是一个Binder对象,实现类是Seession,addToDisplay方法通过IPC调用WindowManagerService的addWindow(...)方法来添加Window;
requestLayout()方法调用scheduleTraversals()方法,后面异步方法刷新请求

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

在TraversalRunnable的run方法里面调用doTraversal()方法,doTraversal()方法会执行performTraversals()方法,后面就是view的三个流程

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
View绘制流程

ViewRootImpl除了绘制view,还包括分发底层传递的行为事件。如通过WindowInputEventReceiver获取传递过来的点击事件,通过handler转发一直传递到Activity,大致流程:

硬件 --> ViewRootImpl --> DecorView --> PhoneWindow --> Activity

Activity不负责视图控制,一个Activity包含一个Window,Windo表示一个窗口
WIndow是视图承载器,内部持有DecorView,DecorView是view的根布局;Window是抽象类,真正持有DecorView是PhoneWindow。Window通过WindowManger将DecorView添加进来,将DecorView交给ViewRoot进行绘制和其他交互操作。
DecorView是Fragment子类,为Android视图树的根节点。
ViewRootImpl通过IWindow连接WindowmangerService和DecorView。View绘制流程也是ViewRoot完成。ViewRoot不属于View树一部分,可以接收事件分发,以及界面刷新等

视图关系

Activity类似控制器,不负责视图部分。Window是承载器,装在视图;DecorView是顶层视图,ViewRootImpl连接器,负责事件传递和用户交互。

上一篇下一篇

猜你喜欢

热点阅读