Android Activity创建到View的显示过程

前言

系列文章:

Android Activity创建到View的显示过程
Android 四大组件通信核心
Android 系统启动到App 界面完全展示终于明白(图文版)

当我们点击桌面图标启动App,到App显示完成,这中间到底经历了什么呢?了解了这部分内容,将会对Activity、Window、View之间联系与区别加深印象,更好指导我们编写代码。
通过这篇文章,你将了解到:

1、Activity创建到onCreate()、onResume方法执行
2、Application创建到onCreate方法执行
3、Activity生命周期监听
4、Window/WindowManager创建与联系
5、WindowManager addView过程
6、ViewRootImpl创建与View三大过程
7、Android屏幕刷新信号简单了解

Android Main方法

写过JavaSE应用或者其它应用的都知道,一个程序的入口是main()方法,那么Android的main()方法在哪呢?
ActivityThread.java

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // Install selective syscall interception
        AndroidOs.install();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

当进程被fork出来后,执行main()方法。该方法很短,简短列出关注的地方:

  • 构造ActivityThread实例
  • 开启Looper循环(主线程也就是UI线程的Looper)

Looper是Android消息(事件)驱动的核心,感兴趣的可移步:Android事件驱动Handler-Message-Looper解析

Application创建过程

来看看ActivityThread.attach()方法:

   @UnsupportedAppUsage
    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());

            //mgr 为ActivityManagerService 实例
            final IActivityManager mgr = ActivityManager.getService();
            try {
                //mAppThread 为ApplicationThread
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }

            //省略
        }
    }

ActivityManagerService.java 方法

    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            
            //把IApplicationThread thread对象传递给AMS,AMS通过thread传递数据到当前进程
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

在attachApplicationLocked(thread, callingPid, callingUid, startSeq);关注两个点:

1、ActivityThread的bindApplication方法
2、mAtmInternal.attachApplication(app.getWindowProcessController()):

先说第一点:

    public final void bindApplication(String processName, ApplicationInfo appInfo,
                                      List<ProviderInfo> providers, ComponentName instrumentationName,
                                      ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                                      IInstrumentationWatcher instrumentationWatcher,
                                      IUiAutomationConnection instrumentationUiConnection, int debugMode,
                                      boolean enableBinderTracking, boolean trackAllocation,
                                      boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                                      CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                                      String buildSerial, AutofillOptions autofillOptions,
                                      ContentCaptureOptions contentCaptureOptions) {
        //省略
        AppBindData data = new AppBindData();
        //省略
        //切换到主线程
        sendMessage(H.BIND_APPLICATION, data);
    }

接着在handleMessage()里接收到H.BIND_APPLICATION信息后调用handleBindApplication(data),该方法里主要关注以下几点:

    private void handleBindApplication(AppBindData data) {
        //省略
        if (ii != null) {
            //省略
        } else {
            //创建Instrumentation 对象,ActivityThread持有该对象引用
            //Application、Activity 的创建都是需要调用instrumentation相关方法
            mInstrumentation = new Instrumentation();
            mInstrumentation.basicInit(this);
        }
        //省略
        Application app;
        try {
            //A
            //info 是LoadedApk类型,顾名思义,存放的是apk包的一些信息,如应用名,数据存储目录等
            app = data.info.makeApplication(data.restrictedBackupMode, null);
            
            //省略
            try {
                //B
                //app创建完毕,调用方法通知
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
               //省略
            }
        } finally {
            //省略
        }
    }

继续分析上述代码注释里的A、B两点。
先来看看A
LoadedApk.makeApplication()方法:

    public Application makeApplication(boolean forceDefaultAppClass,
                                       Instrumentation instrumentation) {
        //传过来的instrumentation=null
        //app已经创建过,无需创建
        if (mApplication != null) {
            return mApplication;
        }

        Application app = null;

        String appClass = mApplicationInfo.className;
        //省略
        try {
            //获取ClassLoader 
            java.lang.ClassLoader cl = getClassLoader();
            //省略
            
            //创建app 的context,注意并不是app本身
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            
            //通过Instrumentation 创建app
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            
            appContext.setOuterContext(app);
        } catch (Exception e) {
            //省略
        }
        
        //赋值
        mApplication = app;
        //省略
        return app;
    }

创建Application对象交给了Instrumentation.newApplication方法:

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        //通过反射创建Application对象,会调用默认构造方法
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        
        //将ContextImpl对象赋值给Application的mBase引用
        app.attach(context);
        return app;
    }

再来看看B

    public void callApplicationOnCreate(Application app) {
        //实际就是调用Application的onCreate方法通知App创建完毕
        app.onCreate();
    }

我们现在创建Application子类App

public class App extends Application {
    public App() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }
}

通过上述分析,可以知道App()、onCreate()的调用时机了。至此Application创建过程分析完毕。

Activity创建过程

Application创建完毕,就该启动Activity了,就是我们熟知的“MainActivity”了。之前说的attachApplicationLocked()里的第二个点:mAtmInternal.attachApplication(app.getWindowProcessController());
mAtmInternal是ActivityTaskManagerService类型

        @Override
        public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
            synchronized (mGlobalLockWithoutBoost) {
                return mRootActivityContainer.attachApplication(wpc);
            }
        }

ActivityStackSupervisor.java


    boolean attachApplication(WindowProcessController app) throws RemoteException {
        final String processName = app.mName;
        //省略
        final int size = mTmpActivityList.size();
        for (int i = 0; i < size; i++) {
            final ActivityRecord activity = mTmpActivityList.get(i);
            if (activity.app == null && app.mUid == activity.info.applicationInfo.uid
                    && processName.equals(activity.processName)) {
                try {
                    //启动activity
                    if (mStackSupervisor.realStartActivityLocked(activity, app,
                            top == activity /* andResume */, true /* checkConfig */)) {
                        didSomething = true;
                    }
                } catch (RemoteException e) {
                }
            }
        }

        //省略
        return didSomething;
    }

接着调用:mService.getLifecycleManager().scheduleTransaction(clientTransaction);
LaunchActivityItem传递到ActivityThread,回到了我们熟悉的地方。最终调用ActivityThread里的handleLaunchActivity()方法:

    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
                                         PendingTransactionActions pendingActions, Intent customIntent) {
        //省略
        //初始化WindowManagerService,后面添加窗口会用到
        WindowManagerGlobal.initialize();
        final Activity a = performLaunchActivity(r, customIntent);
        //省略
        return a;
    }

重点在performLaunchActivity里。

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        //省略

        //创建ContextImpl类型的上下文
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            //和App创建过程一样,Instrumentation通过反射构造Activity实例
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
        } catch (Exception e) {
        }

        try {
            //创建app,因为之前已经创建过,因此这里直接返回Application对象
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            
            //省略

            if (activity != null) {
                Window window = null;
                appContext.setOuterContext(activity);
                //重点方法 A
                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, r.configCallback,
                        r.assistToken);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }

                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 {
                    //通知Activity创建成功,重点方法 B
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                
                //记录activity
                r.activity = activity;
            }

        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
        }

        return activity;
    }

重点方法 A
Activity对象创建完毕后,需要关联一些属性,实际上就是初始化其成员变量,比如Context、Window、WindowManager、Application等。

    Activity.java
    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,
                      Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
        //关联mBase
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        //创建window,window是抽象类,这里是创建其子类PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        //window一些回调接口,比如触摸/物理按键事件分发,焦点变化,依附/去依附 window等
        mWindow.setCallback(this);
        //ui线程即是当前线程
        mUiThread = Thread.currentThread();
        //ActivityThread
        mMainThread = aThread;
        //引用Instrumentation
        mInstrumentation = instr;
        //记录token
        mToken = token;
        //记录Application
        mApplication = application;
        //标题
        mTitle = title;
        
        //创建windowManager,并作为Window的成员变量
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        
        //Activity WindowManager变量赋值
        mWindowManager = mWindow.getWindowManager();
        
        //注:以上有些地方省略了
    }

重点方法 B
和Application类似,Activity创建完成后,通知Activity回调其onCreate方法,这动作的发起还是由Instrumentation开始。

ActivityThread.java
    public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
    }
   Activity.java
    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        //Activity里的onCreate方法,子类都会重写这方法
        if (persistentState != null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
    }

    @CallSuper
    protected void onCreate(@android.annotation.Nullable Bundle savedInstanceState) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
        //省略
        //Activity分发创建事件
        dispatchActivityCreated(savedInstanceState);
        //省略
    }

    private void dispatchActivityCreated(@android.annotation.Nullable Bundle savedInstanceState) {
        //Application里的回调集合
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        
        //Activity里的回到集合
        Object[] callbacks = collectActivityLifecycleCallbacks();
        
        //这里的集合是ActivityLifecycleCallbacks类型,我们平时想监听Activity生命周期可以通过
        //registerActivityLifecycleCallbacks()方法 Application和Activity里都有此方法
        if (callbacks != null) {
            for (int i = 0; i < callbacks.length; i++) {
                //通知观察者Activity onCreate()方法已经执行完毕
                ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityCreated(this,
                        savedInstanceState);
            }
        }
    }

到此Application和Activity已经创建完毕。你可能比较疑惑,那View什么时候显示呢?

View的创建过程

新建Activity的时候,会绑定layout,就从这开始分析(此处以继承自AppCompatActivity 为例分析,如果直接继承自Activity,那更简单)。

Activity.java
    protected void onCreate(@Nullable Bundle savedInstanceState) {
         //将Activity window变量赋予AppCompatDelegateImpl
        //mWindow 成员变量
        //AppCompatDelegateImpl 在Activity.attach()时候创建
        super.onCreate(savedInstanceState);
        //绑定layout
        setContentView(R.layout.activity_main);
    }

    public void setContentView(@LayoutRes int layoutResID) {
        //关联布局,最终连接为ViewTree结构
        getDelegate().setContentView(layoutResID);
    }

来看看AppCompatDelegateImpl.java

    public void setContentView(int resId) {
        /**
         * 1、创建DecorView,并将AppCompatDelegateImpl mWindow赋值给DecorView mWindow变量
         * 2、PhoneWindow mDecor 引用持有DecorView对象,也就是说DecorView与PhoneWindow相互持有
         * 对方
         *
         */
        ensureSubDecor();

        //取出DecorView里名为content的子view,并将其里面的子子view移除
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();

        //加载自定义的layout,实际上就是构建View树的过程,一般都是ViewGroup
        //将自定义的layout作为子View add到contentParent里
        //至此DecorView已经有我们自己自定义的内容了
        LayoutInflater.from(mContext).inflate(resId, contentParent);
    }

至此,整个View树就创建出来了,也就是说在Activity创建的时候就把View树也创建了。虽然简单关联了Window和DecorView(互相持有引用),但是貌似并没有看出什么特别的价值,View何时被添加到Window里呢?

WindowManager addView过程

之前说过,Activity生命周期由AMS管理,我们分析了Activity创建通知由AMS发送给ActivityThread,那么Activity的start、resume时,ActivityThread做了哪些处理呢?
来看看handleResumeActivity():

ActivityThread.java
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                     String reason) {
        //最终调用到Activity onResume()
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);

        if (r.window == null && !a.mFinished && willBeVisible) {
            //取出Activity里的window,这是在Window创建时关联上的
            r.window = r.activity.getWindow();
            //取出window里的DecorView,这是在Activity.setContentView(),DecorView创建时关联上的
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            //也是在Activity创建时关联上的 windowManager继承了ViewManager接口
            //windowManager本身也是个接口
            ViewManager wm = a.getWindowManager();
            //window的布局属性,在Window创建时就生成,默认宽高填满父窗口
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            //window 窗口类型
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            //省略
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //重点方法 A windowManager添加DecorView
                    wm.addView(decor, l);
                } else {
                }
            }
        }
        //省略
    }

重点方法 A
wm.addView(decor, l),addView是ViewManager接口里的方法:

    public interface ViewManager
    {
        //添加View
        public void addView(View view, ViewGroup.LayoutParams params);
        //更新View
        public void updateViewLayout(View view, ViewGroup.LayoutParams params);
        //移除View
        public void removeView(View view);
    }

WindowManager是接口,那么它的实现类是哪个呢?答案就是在创建WindowManager的时候:

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

可以看出,WindowManagerImpl是WindowManager的实现类,来看看其addView()

    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //交由WindowManagerGlobal处理,WindowManagerGlobal是个类,提供单例访问
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
WindowManagerGlobal.java
    public void addView(View view, ViewGroup.LayoutParams params,
                        Display display, Window parentWindow) {
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        //省略
        //ViewRootImpl
        ViewRootImpl root;
        
        View panelParentView = null;
        synchronized (mLock) {
            //创建ViewRootImpl对象
            root = new ViewRootImpl(view.getContext(), display);
            //这里传入的View是DecorView,设置DecorView的layoutParam,默认是填充父控件
            view.setLayoutParams(wparams);

            //WindowManagerGlobal是全局共享的
            //可能会有多个DecorView(每个Activity都有,Dialog也有等)
            //因此需要List来记录相关信息
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            
            try {
                //调用ViewRootImpl setView方法
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
            }
        }
    }

WindowManagerGlobal addView最终调用了ViewRootImpl的setView方法:
该方法比较长,选择重点解释:

ViewRootImpl.java
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                //记录DecorView
                mView = view;
                //省略
                //开启View的三大流程(measure、layout、draw)
                requestLayout();
                try {
                    //添加到WindowManagerService里,这里是真正添加window到底层
                    //这里的返回值判断window是否成功添加,权限判断等。
                    //比如用Application的context开启dialog,这里会添加不成功
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
                    setFrame(mTmpFrame);
                } catch (RemoteException e) {
                }
                
                if (mInputChannel != null) {
                    //注册事件监听,当native层触摸事件/物理键 事件到来时先分发到这 
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }

                //设置 ViewParent mParent;
                //该变量记录每个View的父view,在View的invalidate、requestLayout等
                //场合用来一层层往上遍历view树
                //这里记录着:DecorView的Parent是ViewRootImpl
                view.assignParent(this);
                
                //省略
                //输入事件接收
            }
        }
    }

通过mWindowSession.addToDisplay(),我们知道Window已经和WindowManagerService挂上关系了。剩下的就是View本身的measure、layout、draw过程了,实际上入口就是上边的requestLayout()。

View绘制的三大流程

一个View从构造到显示,需要经历以下步骤:

1、创建View对象(构造)
2、确定View占的空间尺寸(measure)
3、确定了空间尺寸,就需要确定摆放在哪个位置(layout)
4、确认了摆放位置,就需要确定在上面展示些什么东西(draw)

requestLayout

下面的内容涉及到Looper,有疑问的可先看此篇:Android事件驱动Handler-Message-Looper解析

ViewRootImpl.java
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            //检查是否是主线程,如果不是则直接抛出异常,ViewRootImpl创建的时候生成一个主线程引用
            //用当前线程和引用比较,如果是同一个则是主线程
            //这也是为什么在子线程对View进行更新、绘制会报错的原因
            checkThread();
            //用来标记需要进行layout
            mLayoutRequested = true;
            //绘制请求
            scheduleTraversals();
        }
    }
    
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            //标记一次绘制请求,用来屏蔽短时间内的重复请求
            mTraversalScheduled = true;
            //往主线程Looper队列里放同步屏障消息,用来控制异步消息的执行
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            //放入mChoreographer队列里
            //主要是将mTraversalRunnable放入队列
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            //省略
        }
    }

这里引入了Choreographer类,该类是ViewRootImpl构造时候创建的,通过ThreadLocal方式获取

Choreographer.java
    private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
                @Override
                protected Choreographer initialValue() {
                    //ViewRootImpl在主线程构造,这里获取的是主线程的looper
                    Looper looper = Looper.myLooper();
                    //构造Choreographer对象
                    Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
                    return choreographer;
                }
            };

    private Choreographer(Looper looper, int vsyncSource) {
        //记录looper
        mLooper = looper;
        //定义Handler接收message
        mHandler = new FrameHandler(looper);
        //定义DisplayEventReceiver子类,用来接送底层刷新信号
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;;
        //内部队列,用来维护各种请求,比如Traversal callback
        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
        for (int i = 0; i <= CALLBACK_LAST; i++) {
            mCallbackQueues[i] = new CallbackQueue();
        }
    }

放入队列:

Choreographer.java
    private void postCallbackDelayedInternal(int callbackType,
                                             Object action, Object token, long delayMillis) {
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            //放入队列
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                //立即执行
                scheduleFrameLocked(now);
            } else {
                //异步执行
            }
        }
    }

最后调用到DisplayEventReceiver scheduleVsync方法:

DisplayEventReceiver.java
    public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                    + "receiver has already been disposed.");
        } else {
            //native 方法,注册同步脉冲信号事件,告诉底层我需要刷新信号了,记得你的刷新时间到了,给我发送信号
            //底层每16ms刷新一次,如果上层没有注册同步脉冲信号事件,则底层刷新的时候不会通知上层。
            nativeScheduleVsync(mReceiverPtr);
        }
    }

好了,到这里requestLayout()已经完成了,就等待底层的刷新信号了。
秉着在哪里注册,就在哪里接收的原则,来看看DisplayEventReceiver类,找到了dispatchVsync方法:

DisplayEventReceiver.java
    // Called from native code.
    @SuppressWarnings("unused")
    @UnsupportedAppUsage
    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
        //由DisplayEventReceiver子类FrameDisplayEventReceiver重写
        onVsync(timestampNanos, physicalDisplayId, frame);
    }

DisplayEventReceiver 是抽象类,其子类是FrameDisplayEventReceiver

FrameDisplayEventReceiver.java
    public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
        //省略
        //构造Message,并使用this,也就是回调自身run方法
        Message msg = Message.obtain(mHandler, this);
        //设置为异步消息,遇到屏障消息优先执行异步消息
        //确保刷新信号能能够及时执行,也就是view绘制优先级是最高的
        msg.setAsynchronous(true);
        //发送消息
        mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    }

    @Override
    public void run() {
        mHavePendingVsync = false;
        //执行刷新消息
        //最终是取出mCallbackQueues里的方法执行
        doFrame(mTimestampNanos, mFrame);
    }

doFrame里取出的方法在什么时候放入的呢?就是之前

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

放入的。因此doFrame最后会回调mTraversalRunnable run方法

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

    void doTraversal() {
        //没有取消绘制的话则开始绘制
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            //移除同步屏障
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            //真正开始执行measure、layout、draw等方法
            performTraversals();
        }
    }

兜兜转转又回到了ViewRootImpl里。
requestLayout总结为:

1、将绘制请求添加到待执行队列,并发送消息给底层,表示自己有内容需要刷新。这时候reqeustLayout已经执行完毕了。
2、底层间隔时间刷新时,检测到上层的注册信号,因此发送给上层表示我这边已经刷新了,你赶紧换换你的界面吧。
3、收到底层信号时,发送到主线程looper队列里,并标记我这是要告诉别人这是界面刷新的信号哦,耽搁不得,赶紧优先执行。
4、执行第一步的请求,进行view三大绘制流程。

这里有两个问题需要注意一下,还记得代码里提及的一些标记,过滤短时间内的重复请求。

1、mTraversalScheduled 标记,如果这次绘制请求没有被回调执行之前,那么下次请求将忽略,比如短时间内重复的requestLayout。
2、mFrameScheduled 标记,如果底层的刷新信号没有来之前,再次发送给底层的信号将被忽略。

总结

至此,从Application到Activity创建再到View被添加到Window,直至发起绘制整个过程已经梳理完毕。简单归纳一下几者之间关系:

1、Activity通过Window来展示内容
2、Window通过ViewRootImpl管理View Tree
3、真正内容是通过View来展示的

最后用一张图来言简意赅表明整个过程:


image.png

requestLayout时用图表示:


image.png

本文基于Android 10.0源码。

如果您喜欢,请点赞,您的鼓励是我前进的动力。

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

推荐阅读更多精彩内容