理解Activity与显示的关系(1)

简介

我们知道在Android系统中Activity代表一个窗口的显示,甚至初学者认为Activity就是一个显示窗口,在Activity中能够完成显示的所有功能,但是这样理解有偏差,Activity之所以能承载显示是由于内部存在很多与显示相关的核心类,Activity只是通过一些管理方法和回调函去处理这些核心类的核心方法。所以我们应该更深层次的接触Activity。

由于笔者之前接触界面开发很少,甚至没有怎么接触界面开发,所以对Activity的源码也不懂,我也是抱着学习的心态,去尝试研究Activity与显示的关系,所以有什么不对或者需要笔者完善的地方希望读者能够提出来,只有提出问题,我才能去主动探求答案找寻真理。更好的分享给大家,达到共同学习共同进步的目的。好了话不多少进入今天的主题。

源码分析

关于Activity的启动流程并不是今天的重点,所以我大概提下Activity的启动过程,我们重点在于后面

我们之前分析过APP进程启动的过程会启动Activity,我们就从进程启动后进入Activity启动流程分析

AMS.startProcessLocked

private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {
    ...
    ////只有当系统启动完,或者app允许启动过程允许,则会true
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    thread.bindApplication(...);
    if (normalMode) {
        if (mStackSupervisor.attachApplicationLocked(app)) {
            didSomething = true;
        }
    }
    ...
}
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!isFrontStack(stack)) {
                continue;
            }
            //获取前台stack中栈顶第一个非finishing的Activity
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        //真正的启动Activity
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        //启动Activity不成功,则确保有可见的Activity
        ensureActivitiesVisibleLocked(null, 0);
    }
    return didSomething;
}

ASS.realStartActivityLocked

final boolean realStartActivityLocked(ActivityRecord r,
        ProcessRecord app, boolean andResume, boolean checkConfig)
        throws RemoteException {
    app.thread.scheduleLaunchActivity(...);
}

ApplicationThread.java

public final void scheduleLaunchActivity(...) {
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

ActivityThread.java::H

public void handleMessage(Message msg) {
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
            r.packageInfo = getPackageInfoNoCheck(
                    r.activityInfo.applicationInfo, r.compatInfo);
            handleLaunchActivity(r, null);
        } break;
        ...
    }
}

ActivityThread.handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;
    //最终回调目标Activity的onConfigurationChanged()
    handleConfigurationChanged(null, null);
    //初始化wms
    WindowManagerGlobal.initialize();
    //最终回调目标Activity的onCreate
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        //最终回调目标Activity的onStart,onResume.
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);
        if (!r.activity.mFinished && r.startsNotResumed) {
            r.activity.mCalled = false;
            mInstrumentation.callActivityOnPause(r.activity);
            r.paused = true;
        }
    } else {
        //存在error则停止该Activity
        ActivityManagerNative.getDefault()
            .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
    }
}

我们现在涉及到了两个关键点

  • 现在Activity a = performLaunchActivity(r, customIntent);Activity生产出来了
  • 最终调用handleResumeActivity()目前也看不出这个方法干啥

我们就针对这两个核心调用进行分析

1. Activity a = performLaunchActivity(r, customIntent)

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();
        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 {
        //创建Application对象
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);

            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;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            ...
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                ...
            }
        }
        r.paused = true;

        mActivities.put(r.token, r);

    }  catch (Exception e) {
        ...
    }

    return activity;
}

我们通过这段代码可以看出来

  • 根据类名使用反射创建一个Activity实例化对象
  • 调用Activity的onCreate方法

我们结合上面可以知道是在主线程中执行,所以Activity.onCreate()方法是在主线程中调用的,一般情况下我们会在onCreate()方法中使用setContentView()进行设置UI的外观。

handleResumeActivity

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);
            }
        ...
}

这里有几个重点:

  • r.window = r.activity.getWindow()出现了window
  • View decor = r.window.getDecorView()出现了view
  • ViewManager wm = a.getWindowManager()出现了ViewManager

这部分和UI有关,但是我们在这块并不知道哪里来的这些变量,突然就冒出来让我们有点不知所措。所以我们回想一下,刚才调用了onCreate()之后才发生这些的,onCreate()是不是我们要调用setContentView设置一些什么东东呢哈哈。

setContentView()

Activity.java

private Window mWindow;
public void setContentView(View view) {
    getWindow().setContentView(view);
    initWindowDecorActionBar();
}
public Window getWindow() {
    return mWindow;
}

mWindow是什么,在哪里创建的?
那么我们就只能在Activity创建的过程中寻找答案.

java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);

Instrumentation.java

public Activity newActivity(Class<?> clazz, Context context, 
        IBinder token, Application application, Intent intent, ActivityInfo info, 
        CharSequence title, Activity parent, String id,
        Object lastNonConfigurationInstance) throws InstantiationException, 
        IllegalAccessException {
    Activity activity = (Activity)clazz.newInstance();
    ActivityThread aThread = null;
    activity.attach(context, aThread, this, token, 0, application, intent,
            info, title, parent, id,
            (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
            new Configuration(), null, null);
    return activity;
}

    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*/);

        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }

        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;
    }

在Context中定义了:public static final String WINDOW_SERVICE = "window";

我们看到了

  • mWindow = new PhoneWindow(this);
  • mWindow.setWindowManager(
    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE)...);

所以这个时候我们明白在Activity中mWindow是PhoneWindow对象,并且mWindow设置了名称为window的服务

我们继续回到setContentView的这个话题,我们现在知道是调用PhoneWindow的setContentView了


    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            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 {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

调用了两个核心:

  • installDecor()
  • mContentParent.requestApplyInsets();
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();// return new DecorView(getContext(), -1);
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
    }
    
    final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
            R.id.decor_content_parent);
    if (decorContentParent != null) {
        mDecorContentParent = decorContentParent;
        mDecorContentParent.setWindowCallback(getCallback());
        if (mDecorContentParent.getTitle() == null) {
            mDecorContentParent.setWindowTitle(mTitle);
        }
    ...
}

generateLayout()

public class PhoneWindow extends Window implements MenuBuilder.Callback {
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

protected ViewGroup generateLayout(DecorView decor) {
    ...
    mDecor.startChanging();
    //此时的layoutResource代表整个界面
    View in = mLayoutInflater.inflate(layoutResource, null);
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    ...
    return contentParent;
}

Window.java

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

代码可以看出来,我们先加载View然后添加到decor中,对于这个contentid也只不多是DecorView的一部分。

所以我们通过包含关系形容他们

PhoneWindow
    DecorView
        MyView

我们在通过文字来描述一下这个关系

我们在Activity通过反射创建之后会调用Activity.attach()方法在这个方法中会创建PhoneWindow和对PhoneWindow设置名称是window的服务,当我们在Activity.onCreate()方法中使用setContentView的时候会创建DecorView,然后将整个一些元素添加到DecorView中

所以我们在Activity中的那些界面其实最根部的设置是由DecorView这个View保存设置的。

目前为止我们通过:

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);
            }
        ...
}

这个方法得知,现在PhoneWindow,DecorView都有了,只是欠缺ViewManager,我们需要分析ViewManager


public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
private WindowManager mWindowManager;
ViewManager wm = a.getWindowManager();//return mWindowManager

我们在attach方法中进行创建

final void attach(...) {
        attachBaseContext(context);
    mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                ...);
    ...
    mWindowManager = mWindow.getWindowManager();
}

我们知道mWindow是PhoneWindow对象,在其父类Window中实现了getWindowManager方法:

public WindowManager getWindowManager() {
    return mWindowManager;
}

同样在PhoneWindow的父类Window中构造并且设置了WindowManager

 public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

WindowManagerImpl.java

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mDisplay, parentWindow);
}

到这里我们就知道对应ViewManager是WindowManagerImpl对象

也就是说我们在Activity.attach()中创建了WindowManagerImpl对象然后在handleResumeActivity方法中利用WindowManagerImpl将产生的decorView添加到wm中。

在小结:

ActivityThread.handleLaunchActivity()
    Activity a = performLaunchActivity()
        activity = mInstrumentation.newActivity()
        activity.attach()
            mWindow = new PhoneWindow(this);
            mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)...);
                mWindowManager = ((WindowManagerImpl)mContext.getSystemService("window")).createLocalWindowManager(this);
                    return new WindowManagerImpl(mDisplay, parentWindow)
            mWindowManager = mWindow.getWindowManager()
        mInstrumentation.callActivityOnCreate(activity...)
            activity.performCreate(...)
                onCreate(...)
                    setContentView(R.id.xx)
                        getWindow().setContentView(layoutResID);
                            PhoneWindow.installDecor()
                                generateDecor()
                                    return new DecorView();
    handleResumeActivity()
        wm.addView(decor...)
            mGlobal.addView(view...)
                root = new ViewRootImpl(...)
                    Surface mSurface = new Surface()//成员变量
                    mWindowSession = WindowManagerGlobal.getWindowSession()
                        IWindowManager windowManager = getWindowManagerService()
                            sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"))
                        sWindowSession = windowManager.openSession()
                            Session session = new Session()//在WMS中
                    mWindow = new W(this)//构造函数
                root.setView(view...)
                    mWindowSession.addToDisplay(mWindow...)
                        return mService.addWindow(...)//mService是WMS
                            token = new WindowToken(...)
                            WindowState win = new WindowState(...)
                            win.attach()
                                mSession.windowAddedLocked();
                                    mSurfaceSession = new SurfaceSession();
                            mWindowMap.put(client.asBinder(), win)//将这个window加入列表中
                    requestLayout()
                        scheduleTraversals()
                            run(){doTraversal()}
                                performTraversals()

我们在app进程启动的时候会初始android环境,然后过程中会启动activity,在启动activity的时候是通过反射方法生成Activity对象调用attach之后然后会调用Activity的OnCreate()方法在调用attach过程中会生成一些核心的对象其中主要有PhoneWindow对象与WindowManagerImpl对象,当调用onCreate()的时候会使用setContentView做设置布局,这个时候就会产生mDecor(DecorView)最后执行到handleResumeActivity这个方法也就是对应Activity声明周期回调的OnResume方法,此时将DecorView对象添加到WindowManagerImpl中进行管理。

后面大概的内容还有个ViewRoot,Surface,WMS,RawBuffer等等。因为我们到目前为止知道DecorView是根布局,但是我们并牵扯到绘制,按键监听消息通信方面的知识所以我们以后的分析会更难,因为牵扯到通信模块与WMS的管理模块了,不要灰心一点点看总会进步。

ViewRoot剖析

为什么我们要剖析ViewRoot呢?到目前为止我们发现我们并没有与任何绘制有关的进程进行通信所以我们需要继续剖析Android系统如何进行绘制管理的。所以ViewRoot是与WMS,Surface打交道的枢纽。

我们在ActivityThread.handleResumActivity()的时候会有如下代码:

ActivityThread.handleResumActivity(){
    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的add方法,但是是谁实现了ViewManager呢,ViewManager在这里只是接口。

我们这里具体是在attach中得到wm的:

Activity.attach()

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

其中setWindowManager:

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    mAppToken = appToken;
    mAppName = appName;
    mHardwareAccelerated = hardwareAccelerated
            || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

WindowManagerImpl.createLocalWindowManager()

   public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

注意了主角来了:

也就是说我们上面:

ActivityThread.handleResumActivity(){
    ...
     wm.addView(decor, l);
    ...
}

是调用WindowManagerImpl的addView()
具体是:

WindowManagerImpl.java

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

这个mGlobal是:

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

也就是WindowManagerImpl也没有实权,实权具体在mGlobal中:


    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            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;
        }
    }

在这里我们看到了

  • root = new ViewRootImpl(view.getContext(), display);
  • mViews.add(view);
  • mRoots.add(root);
  • mParams.add(wparams);
  • root.setView(view, wparams, panelParentView);
    生成ViewRoot对象,然后将这个View也就是到目前为止是DecorView设置到ViewRoot对象中。

所以下面才是正儿八经剖析ViewRoot开始

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
root = new ViewRootImpl(...)
    Surface mSurface = new Surface()//成员变量
    mWindowSession = WindowManagerGlobal.getWindowSession()
        IWindowManager windowManager = getWindowManagerService()
            sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"))
        sWindowSession = windowManager.openSession()
            Session session = new Session()//在WMS中
    mWindow = new W(this)//构造函数

ViewRootImpl的构造

public ViewRootImpl(Context context, Display display) {
    ...
    mContext = context;
    mWindowSession = WindowManagerGlobal.getWindowSession();//Session
    mWindow = new W(this);
    ...
}

核心在于这个W和Session这两个都是Binder的实现类

  • mWindowSession: 引用着WMS的Session对象
  • mWindow是Binder实体类在ViewRootImpl中

最终形成的关系:

APP 引用变量 WMS
WindowManagerGlobal --IWindowSession--> Session
W <--IWindow-- WindwState

现在我们知道ViewRoot中存在两个Binder类,一个Session代理,一个W实体。所以ViewRoot是和WMS通信的核心类

在ViewRoot中还有个核心方法requestLayout()

当setView的时候调用requestLayout()这个方法进行界面的绘制

ViewRootImpl.java

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

其中:

//将runnable发送给handler执行
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

这句目的是将mTraversalRunnable发送给handler进行处理

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        performTraversals();
        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

在这个函数中会调用测量布局绘制那些逻辑

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容