Framework学习之路(一)—— UI绘制深入源码分析

Framework学习之路(一)—— UI绘制深入源码分析

本篇为笔者对Android SDK 33版本的UI绘制入口进行追踪的过程,主要作笔记作用。由于笔者经验尚浅,水平也有限,所以会存在很多不足的地方。如果有大神发现问题,可以在评论区指出。


章节目录:

​ 一、APP程序入口

​ 1、 ActivityThread的main方法、重要属性及其父类的介绍

​ 1. ActivityThread及其main函数的介绍

​ 2. ActivityThread重要属性的介绍

​ 3. 启动主线程的Looper

​ 4. ActivityThread的父类ClientTransactionHandler

​ 2、 Application的创建与启动

​ 1. 创建ActivityThread实例

​ 2. 通过AMS获取Application信息

​ 3. 创建Instrumentation实例

​ 4. 创建Application实例

​ 5. 启动Application

​ 3、Activity的创建和启动

​ 1. 系统进程的准备工作

​ (1) ActivityTaskManagerService

​ (2) WindowContainer

​ (3) ClientTransaction

​ [1] 初始化mDecor属性

​ [2] 初始化mContentParent属性

​ 附录:ActivityTaskManagerService的启动

​ 2. 创建Activity实例

​ 附录:AppComponentFactory

​ 3. 启动Activity

​ 二、UI绘制流程

​ 1、Activity加载XML文件的过程

​ 1. PhoneWindow的初始化

​ (1) 创建PhoneWindow

​ (2) PhoneWindow的重要属性——mDecor和mContentParent

​ (3) mDecor和mContentParent属性的初始化

​ 附录一:常见的根布局——screen_simple.xml

​ 附录二:DecorVIew添加RootView

​ 2. 加载自定义布局

​ 2、AppCompatActivity加载XML文件的过程

​ 1. 初始化PhoneWIndow的mDecor和mDecorContentParent属性

​ 2. 初始化AppCompatDelegateImpl的mSubDecor属性

​ 3.加载自定义布局

​ 附录一:简单根布局abc_screen_simple.xml

​ 3、UI绘制过程

​ 1. 调用Activity的onResume方法

​ 2. ViewRootImpl进行UI绘制的过程

​ (1) View绘制三大流程的入口

​ (2) View绘制三大流程之onMeasure方法

​ (3) View绘制三大流程之onLayout方法

​ (4) View绘制三大流程之onDraw方法

​ 附录一:将ViewRootImpl添加为DecorView的父布局

​ 附录二:UI线程检查

一、APP程序入口

1、ActivityThread的main方法、重要属性及其父类的介绍

1. ActivityThread及其main函数的介绍
/**
* ActivityThread是一个handeler类,这个看他的父类就可以知道
*/
public final class ActivityThread extends ClientTransactionHandler {
    ...
    public static void main(String[] arg) {
        //CloseGuard类实现了一种机制用于检查是否有内存泄露,,默认是关闭的,可以通过setEnabled(true)开启
        CloseGuard.setEnabled(false);
        
        //初始化Environment类,主要是一些目录的设置
        //比如我们通常用的获取外部储存路径的函数Environment.getExternalStorageDirectory()的返回值就是在这里进行初始化的
    	Environment.initForCurrentUser();
        
        //确保 TrustedCertificateStore 在正确的位置查找 CA 证书
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        
        //调用每个进程的主线模块初始化
        initializeMainlineModules();
        
        //初始化Handler中的Looper对象
        Looper.prepareMainLooper();
        
        ...
        //创建一个ActivityThread    
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
		//初始化专门处理消息的handler对象
        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);
        //开始循环主线程里面的MessageQueue
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    ...
}
2. ActivityThread重要属性的介绍

首先我们需要知道一点,ActivityThread不会持有Activity或者ActivityThread里面的任何东西,真正管理我们application或者activity的是AMS或者PMSActivityThread就是一个handler,它会不停的和我们的AMS或者PMS进行通信,然后得到结果,再来通过消息队列来执行它的handlerMessage。

我们接着看ActivityThread的几个主要的属性:

  • mAppThread: ActivityThread不能直接和系统进行通讯,需要通过Binder,所以我们用ActivityTread的main方法不能直接获取Application(也就是不能直接启动应用),需要通过作为桥梁的ApplicationThread进行调用。而AMS作为桥梁的一端,会持有我们的ApplicationThread,然后来进行回调。(这里注意ApplicationThread是ActivityThread的子类)
  • mLooper:ActivityThread作为一个handler想持续不停的往MessageQueue里面拿消息,肯定需要looper一直去轮询,也就是这里的mLooper属性。
  • mInstrumentation: Instrumentation是所有的Application和Activity用来跟踪生命周期的类。ActivityThread不会直接的去执行某一个组件的生命周期方法,比如对于Application和Activity,它真正的启动是经过Instrumentation,Instrumentation是真正管理它们生命周期的类
public final class ActivityThread extends ClientTransactionHandler {
    //ApplicationThread是ActivityThread与AMS通讯的桥梁,它作为服务端,接收ActivityManagerService的指令并执行
    final ApplicationThread mAppThread = new ApplicationThread();

    final Looper mLooper = Looper.myLooper();
    ...  
    //真正管理Activity生命周期的类
    Instrumentation mInstrumentation;  
}
3. 启动主线程的Looper
//ActivityThread.java#main
Looper.prepareMainLooper(); //初始化Handler中的Looper对象

//Looper.java
...
private static Looper sMainLooper;  
...
public static void prepareMainLooper() {
    //设置当前线程为不可退出的线程
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //将主线程赋值给sMainLooper,这也是我们可以直接通过Looper.getMainLooper()获取主线程的原因
        sMainLooper = myLooper();
    }
}

public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}

这里我们注意,main方法运行完就退出了,但是我们有个looper.loop,一直在循环的接受消息和发送消息,所以它会一直在运行,不会退出。

//ActivityThread.java#main
Looper.loop(); //开始循环主线程里面的MessageQueue
4. ActivityThread的父类ClientTransactionHandler

个人见解:ClientTransactionHandler既然是Handler,显然它会具备sendMessage方法,不过它并没有继承我们熟悉的Handler类,也就是说它虽然具备处理消息的职责,但真正处理消息的可能另有其人,比如ActivityThread就把真正处理消息的任务下发给了Handler类型的mH成员变量,这个后面会讲。

//ClientTransactionHandler.java
abstract void sendMessage(int what, Object obj);

我们看到ClientTransactionHandler里面有很多和Activity的生命周期有关的方法。

public abstract class ClientTransactionHandler {
    ...
	public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing,
            int configChanges, boolean getNonConfigInstance, String reason);

    public abstract void handlePauseActivity(@NonNull ActivityClientRecord r, boolean finished,
            boolean userLeaving, int configChanges, PendingTransactionActions pendingActions,
            String reason);

    public abstract void handleResumeActivity(@NonNull ActivityClientRecord r,
            boolean finalStateRequest, boolean isForward, String reason);
    
    public abstract void handleTopResumedActivityChanged(@NonNull ActivityClientRecord r,
            boolean isTopResumedActivity, String reason);

    public abstract void handleStopActivity(@NonNull ActivityClientRecord r, int configChanges,
            PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);
	...
}

AMS通过ApplicationThread封装好数据,回调到ActivityThread,ActivityThread就可以通过发通知的方式,发给Handler,然后通过Handler的方法来执行相应的操作。

我们发现AMS->ApplicationThread->ActivityThread三者之间的分工非常明确,有点像MVP模式:

  • AMS(M层):数据管理者。
  • ApplicationThread(P层):通讯桥梁。
  • ActivityThread(V层):具体逻辑的执行者。

这里有一点值得注意,Activity是在主线程中创建的,也就说ActivityThread的main方法所在的线程就是APP的主线程,这点在上面看到ActivityThread的Looper时就可见一斑。因为主线程是main方法所在的线程,也就是APP进程的第一个线程,所以主线程无法修改。

2、 Application的创建与启动

1. 创建ActivityThread实例

我们启动应用,就必须先创建Application。由于不确定项目中具体的Application类,所以不能通过new来创建,而是需要通过AMS去获取Application的类名信息,再通过反射将它实例化;若AMS获取不到,再使用new的方式创建默认的Application。

//ActivityThread.java#main   
ActivityThread thread = new ActivityThread();//创建一个ActivityThread 
thread.attach(false, startSeq);
2. 通过AMS获取Application信息

我们先看看attach方法做了什么?

//ActivityThread.java   
private static volatile ActivityThread sCurrentActivityThread;
...
final ApplicationThread mAppThread = new ApplicationThread();
...
private void attach(boolean system, long startSeq) {   
    //ActivityThread赋值给自己的静态成员变量,是为了方便外部通过静态方法调用自己,算是单例模式的变种
    sCurrentActivityThread = this;
    ... 
    //获取到ActivityManagerService的代理对象IActivityManager
    final IActivityManager mgr = ActivityManager.getService();
    try {
        //调用AMS的attachApplication方法,mAppThread作为沟通桥梁传入该方法
        mgr.attachApplication(mAppThread, startSeq);   //PS:这里是AMS在attach方法里唯一调用地方
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
    ...
}
    

我们看一下上面的IActivityManager的代理接口是如何获取的?

//ActivityThread.java#attach
final IActivityManager mgr = ActivityManager.getService();

//ActivityManager.java#getService
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
    @Override
    protected IActivityManager create() {
        //通过binder机制进行进程通讯 从Activity系统服务中获取到AMS的代理对象
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
        final IActivityManager am = IActivityManager.Stub.asInterface(b);
        return am;
    }
};

我们可以看到IActivityManager从系统服务管理者ServiceManager中获取到了可以和系统服务进程的AMS进行远程通讯Binder通道。

接下来看看ActivityThread的attach方法,在获取AMS的代理对象后,做了什么事情?

//ActivityThread.java#attach
mgr.attachApplication(mAppThread, startSeq);

//ActivityManagerService.java#attachApplication
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        //从Binder中获取到一些进程信息
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq); //* 重点方法
        Binder.restoreCallingIdentity(origId);
    }
}

//ActivityManagerService.java#attachApplicationLocked
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
    ///(1)
    //查找正在附加的应用程序记录...
    //如果我们在多个进程中运行,则通过PID,或者如果我们使用匿名线程模拟进程,则只需拉取下一个应用程序记录。
    ProcessRecord app; //(2) 储存进程信息,attachApplicationLocked方法里面存在大量对该对象及其属性进行赋值的代码
   	...
    //(3)
        if (app.getIsolatedEntryPoint() != null) {
            // This is an isolated process which should just call an entry point instead of
            // being bound to an application.
            thread.runIsolatedEntryPoint(
                app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
        } else if (instr2 != null) {
            thread.bindApplication(processName, appInfo,
                                   app.sdkSandboxClientAppVolumeUuid, 
                                   app.sdkSandboxClientAppPackage,
                                   ...);
        }else {
            thread.bindApplication(processName, appInfo, 
                                   app.sdkSandboxClientAppVolumeUuid, 
                                   app.sdkSandboxClientAppPackage,
                                   ...);
        }
    ...
}

//ActivityThread$ApplicationThread.java#bindApplication
@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,
                                  String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage,
                                  ...) {
	...
    AppBindData data = new AppBindData(); //(4)
    data.processName = processName;
    data.appInfo = appInfo;
    ...  
    sendMessage(H.BIND_APPLICATION, data); //(5)
}

//ActivityThread.java#sendMessage
 private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
     if (DEBUG_MESSAGES) {
         Slog.v(TAG,
                "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj);
     }
     Message msg = Message.obtain();
     msg.what = what;
     msg.obj = obj;
     msg.arg1 = arg1;
     msg.arg2 = arg2;
     if (async) {
         msg.setAsynchronous(true);
     }
     mH.sendMessage(msg); //(6)
 }

//ActivityThread$H.java#handleMessage
 public void handleMessage(Message msg) {
     if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
     switch (msg.what) {
         case BIND_APPLICATION:
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
             AppBindData data = (AppBindData)msg.obj;
             handleBindApplication(data); //(7)
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             break;
             ...
     }
     ...
 }

① 在创建Application之前,要从AMS中获取Application的一些比较重要的信息。比如我们的Application到底是自己创建的,还是别人传过来的?还是系统原生的,或者系统自带的,或者系统自己创建的?我们都要进行判断,而这些信息都保留在AMS里面。

② ProcessRecord是进程记录者,该类专门储存当前进程的所有信息,这就说明它也保存了Application的一些信息。(该类存在很多成员变量,如果我们看到类似的成员变量多的类,就可以把它认为是专门储存数据的类)

③ AMS将数据封装到ProcessRecord等变量之后,通过传入大量参数的形式将信息回调给IApplicationThread。

④ ActivityThread.AppBindData是应用数据的封装类,ApplicationThread把AMS传过来的数据全部都传给了AppBindData,也就是说AppBindData携带了Application的信息。

⑤ 将AppBindData传递给ActivityThread的sendMessage方法。(因为ApplicationThread并不是ActivityThread静态内部类,所以可以直接调用ActivityThread的方法)

⑥ ActivityThread里面所有的通知最终都是在mH里面进行了具体的操作,这个上面有提到。

⑦ handleBindApplication方法对Application进行了绑定。


本小节后续内容,都会在handleBindApplication方法里面展开,我们会看到ActivityThread在handleBindApplication方法里面依次创建了Instrumentation、Application,然后调用了Application的onCreate方法。

3. 创建Instrumentation实例
//ActivityThread.java#handleBindApplication
private void handleBindApplication(AppBindData data) {
	...
    //mInstrumentation在这里进行了初始化
    if (ii != null) {
        initInstrumentation(ii, data, appContext); //* 重点方法
    } else {
        mInstrumentation = new Instrumentation();
        mInstrumentation.basicInit(this);
    }
    ...
}

//ActivityThread.java#initInstrumentation
private void initInstrumentation(
            InstrumentationInfo ii, AppBindData data, ContextImpl appContext) {
    ...
    try {       
        final ClassLoader cl = instrContext.getClassLoader();
        mInstrumentation = (Instrumentation)
            cl.loadClass(data.instrumentationName.getClassName()).newInstance(); //通过反射的方式来创建mInstrumentation的实例
    } catch (Exception e) {
        throw new RuntimeException(
            "Unable to instantiate instrumentation "
            + data.instrumentationName + ": " + e.toString(), e);
    }
    ...
}

4. 创建Application实例

initInstrumentation方法执行结束后,我们得到了mInstrumentation实例,接着我们重新回到ActivityThread的handleBindApplication方法这里,看看Application是如何创建的。

//ActivityThread.java#handleBindApplication
private void handleBindApplication(AppBindData data) {
	...
    //mInstrumentation初始化完成后开始创建Application对象
    Application app;
    ...
    app = data.info.makeApplicationInner(data.restrictedBackupMode, null); //通过LoadedApk创建application
    ...
}

//LoadedApk.java#makeApplicationInner
public final class LoadedApk {
    ...
    //application缓存的实例
    private Application mApplication; 
    ...
    //我们在此处缓存此进程中每个包的实例化应用程序对象。
    private static final ArrayMap<String, Application> sApplications = new ArrayMap<>(4);
    ...
    public Application makeApplicationInner(boolean forceDefaultAppClass,
                                            Instrumentation instrumentation) {
        return makeApplicationInner(forceDefaultAppClass, instrumentation,
                                    /* allowDuplicateInstances= */ false);
    }

    private Application makeApplicationInner(boolean forceDefaultAppClass,
                Instrumentation instrumentation, boolean allowDuplicateInstances) {
        if (mApplication != null) {
            //如果application已经存在,则直接返回
            return mApplication; 
        }
        ...
        //从缓存的sApplications集合中尝试获取Application
        synchronized (sApplications) {
            final Application cached = sApplications.get(mPackageName); 
            if (cached != null) {
                ...
                if (!allowDuplicateInstances) {
                    mApplication = cached;
                    return cached;
                }
            }
        }
        
        //创建Application对象
      	Application app = null;
        ...
        //获取application类名
        String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(myProcessName);       
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }
        ...
            app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext); //(1)
        ...            
        //缓存Application
       	mActivityThread.mAllApplications.add(app);
        mApplication = app;
        if (!allowDuplicateInstances) {
            synchronized (sApplications) {
                sApplications.put(mPackageName, app);
            }
        }
    }
}

//Instrumentation.java#newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
    throws InstantiationException, IllegalAccessException, 
ClassNotFoundException {
    Application app = getFactory(context.getPackageName()).instantiateApplication(cl, className);
    app.attach(context); //application创建后,调用了attach方法,而attach方法里面调用了我们熟知的attachBaseContext方法。
    return app;
}

//AppComponentFactory.java#instantiateApplication
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
                                                   @NonNull String className)
    throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Application) cl.loadClass(className).newInstance(); //(2) 这里就是通过类加载器最终创建了我们的Application
}

① ActivityThread通过的mInstrumentation来创建Application实例。我们之前提过,Application和Activity包括创建和生命周期等操作都是由mInstrumentation来监管的。

② Instrumentation最终通过AppComponentFactory的instantiateApplication方法,使用类加载器创建了Application。

5. 启动Application

我们继续看handleBindApplication方法,在mInstrumentation和app都创建完成后,我们继续跟踪mInstrumentation,就可以看到它使用callApplicationOnCreate方法调用了app的onCreate方法,mInstrumentation监听Application和Activity其实都是通过这样的方式。

调用了onCreate方法后,Application就已经启动了。

//ActivityThread.java#handleBindApplication
private void handleBindApplication(AppBindData data) {
    ...
	mInstrumentation.callApplicationOnCreate(app);
    ...
}

//Instrumentation.java#callApplicationOnCreate
public void callApplicationOnCreate(Application app) {
    app.onCreate();
}

3、Activity的创建和启动

1. 系统进程的准备工作
(1) ActivityTaskManagerService

前面我们在ActivityManagerService的attachApplicationLocked方法中创建了Application,创建完成后,也会在该方法中创建Activity。

个人见解:attachApplicationLocked方法中必然创建了Actiivity,我们回顾上面的ActivityThread的main方法调用AMS的代码,发现只有attach方法沟通了AMS,追踪后可以发现attach方法调用的AMS方法中,核心逻辑都在attachApplicationLocked方法里面,也就是说在应用启动过程中,attachApplicationLocked方法就是AMS的核心逻辑,这也就意味着启动Application和MainActivity的逻辑也必然在此方法中。

所以我们就attachApplicationLocked方法往下跟踪,发现application启动后,执行了下面的代码。

//ActivityManagerService.java#attachApplicationLocked
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
    ...
    // 查看此进程中最可见的活动是否正在等待运行...
    if (normalMode) {
        try {
            didSomething = mAtmInternal.attachApplication(app.getWindowProcessController()); // (1)
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }

    //查找应在此进程中运行的任何服务...
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName); // (2)
            checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }

}

①Activity创建与启动的逻辑就在mAtmInternal的attachApplicationLocked方法中。

② mServices是ActiveServices,其attachApplicationLocked方法创建的是Service而不是Activity,这里不要搞混。


那么我们来看看mAtmInternal究竟是谁?

//ActivityManagerService.java
public ActivityTaskManagerInternal mAtmInternal;

//ActivityTaskManagerInternal.java
public abstract class ActivityTaskManagerInternal {
    ...
}

//ActivityManagerService.java#Constructor
public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
    ...
    mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); //这里创建并启动了Activity
    ...
}

//LocalServices
public final class LocalServices {
    ...
    private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
            new ArrayMap<Class<?>, Object>();
    
    /**
    * 返回实现指定接口的本地服务实例。
    * 参数:类型 – 服务的类型。
    * 返回:服务对象。
    */
 	public static <T> T getService(Class<T> type) {
        synchronized (sLocalServiceObjects) {
            return (T) sLocalServiceObjects.get(type);
        }
    }

    /**
     * 将指定接口的服务实例添加到本地服务的全局注册表中。
     */
    public static <T> void addService(Class<T> type, T service) {
        synchronized (sLocalServiceObjects) {
            if (sLocalServiceObjects.containsKey(type)) {
                throw new IllegalStateException("Overriding service registration");
            }
            sLocalServiceObjects.put(type, service);
        }
    }   
    
    ...       
}

mAtmInternal是AMS的成员变量,是ActivityTaskManagerInternal抽象类型的实例对象。从AMS的构造方法中,可以发现mAtmInternal是来自LocalServices缓存的某个服务。

这时候想要知道mAtmInternal究竟是什么类型的对象,我们就需要知道是谁把它存到了LocalServices中,但这并不好找。

干脆以“ActivityTaskManager”这个字段来搜索,这时候就发现了一个可疑的类型:ActivityTaskManagerService(ActivityTaskManagerService的启动见本节附录)。

搜索一下“ActivityTaskManagerInternal.class”,果然找到了mAtmInternal的入口。

//ActivityTaskManagerService.java
...
final ActivityTaskManagerInternal mInternal;
...
public ActivityTaskManagerService(Context context) {
    ...
    mInternal = new LocalService();
    ...
}
...
private void start() {
	LocalServices.addService(ActivityTaskManagerInternal.class, mInternal); //ActivityManagerService#mAtmInternal的来源
}

我们发现mInternal是LocalService类型的对象(注意这个LocalService并不是缓存服务的LocalServices),而LocalService是ActivityTaskManagerService的内部类。

//ActivityTaskManagerService$LocalService.java
final class LocalService extends ActivityTaskManagerInternal {
	...
    @Override
    public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
        synchronized (mGlobalLockWithoutBoost) {
            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);
            }
            try {
                return mRootWindowContainer.attachApplication(wpc); //* 核心方法
            } finally {
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            }
        }
    }
	...
}
(2) WindowContainer
//ActivityTaskManagerService$LocalService.java#attachApplication
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
    ...
    return mRootWindowContainer.attachApplication(wpc);
    ...
}

//ActivityTaskManagerService.java
RootWindowContainer mRootWindowContainer;

RootWindowContainer是窗口容器(WindowContainer)的根容器,管理所有的窗口容器,设备上所有的窗口(Window)、显示屏幕(Display)都是由它来管理的。

//RootWindowContainer.java
class RootWindowContainer extends WindowContainer<DisplayContent>
        implements DisplayManager.DisplayListener {
    ...
    private final AttachApplicationHelper mAttachApplicationHelper = new AttachApplicationHelper();
    ...
    boolean attachApplication(WindowProcessController app) throws RemoteException {
        try {
            return mAttachApplicationHelper.process(app);
        } finally {
            mAttachApplicationHelper.reset();
        }
    }
    
    private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {
        ...
        private ActivityRecord mTop;
        ...
        boolean process(WindowProcessController app) throws RemoteException {
            mApp = app;
            for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
                getChildAt(displayNdx).forAllRootTasks(this); //(1)
                if (mRemoteException != null) {
                    throw mRemoteException;
                }
            }
            if (!mHasActivityStarted) {
                ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                        false /* preserveWindows */);
            }
            return mHasActivityStarted;
        }
        
        @Override
        public void accept(Task rootTask) { 
            if (mRemoteException != null) {
                return;
            }
            if (rootTask.getVisibility(null /* starting */)
                    == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
                return;
            }
            mTop = rootTask.topRunningActivity(); //(2)
            rootTask.forAllActivities(this);
        }
        ...
    }
}

① 遍历RootWindowContainer所有的窗口和显示屏幕,这里最终会调用AttachApplicationHelper的accept方法

② Task用来描述一个Activity任务栈,而ActivityRecord记录了Activity的所有信息。这里是通过调用rootTask的topRunningActivity方法获取到栈顶Activity的信息,然后存到了mTop。(这里栈顶Activity并不是我们熟知的Activity,而是记录Activity配置信息的ActivityRecord)

//Task.java#topRunningActivity
class Task extends TaskFragment {
    ActivityRecord topRunningActivity(IBinder token, int taskId) {
        final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning,
        PooledLambda.__(ActivityRecord.class), taskId, token);
        final ActivityRecord r = getActivity(p);
        p.recycle();
        return r;
	}
}

//TaskFragment.java
class TaskFragment extends WindowContainer<WindowContainer> {
    ...
}

//WindowContainer.java#getActivity
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
        InsetsControlTarget {
    ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
                ActivityRecord boundary) {
         ...
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
             ...
             final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
             ...
         }
         ...
    }
}

Task的topRunningActivity方法最终调用了WindowContainer的getActivity方法,该方法遍历Task下所有的窗口。

得到了ActivityRecord后,接着调回了RootWindowContainer$AttachApplicationHelper.java的test方法,尝试创建并启动Activity。

(PS:accept方法和test方法的具体调用方还没仔细找,这里只是猜测)

//RootWindowContainer$AttachApplicationHelper.java
private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {
    boolean process(WindowProcessController app) throws RemoteException {
        ...
        if (!mHasActivityStarted) { //(3)
            ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                                    false /* preserveWindows */); //(4)
        }
        return mHasActivityStarted;
    }
    ...
    @Override
  	public boolean test(ActivityRecord r) {
        if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard
            || r.app != null || mApp.mUid != r.info.applicationInfo.uid
            || !mApp.mName.equals(r.processName)) {
            return false;
        }

        try {
            if (mTaskSupervisor.realStartActivityLocked(r, mApp,
                                                        mTop == r && r.getTask().canBeResumed(r) /* andResume */,
                                                        true /* checkConfig */)) { //(1)
                mHasActivityStarted = true; //(2)
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception in new application when starting activity " + mTop, e);
            mRemoteException = e;
            return true;
        }
        return false;
    }
}

通过调用mTaskSupervisor的realStartActivityLocked方法(见①),真正创建并启动了Activity,如果启动成功设置mHasActivityStarted为true(见②),回到process方法后会判断Activity是否启动成功(见③),如果失败,会调用ensureActivitiesVisible方法确保活动可见(见④)。

我们看看mTaskSupervisor是如何创建Activity的?

(3) ClientTransaction
//RootWindowContainer.java#mTaskSupervisor
ActivityTaskSupervisor mTaskSupervisor;

//ActivityTaskSupervisor.java#realStartActivityLocked
public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
    ...
    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
                                    boolean andResume, boolean checkConfig) throws RemoteException {
   		...
		// 创建活动启动事务。
        final ClientTransaction clientTransaction = ClientTransaction.obtain(
            proc.getThread(), r.token); //(1) 这里的proc.getThread()其实就是ApplicationtThread

        final boolean isTransitionForward = r.isTransitionForward();
        final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
        //* 添加LaunchActivityItem回调对象,这个后面会提到
        clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                                                                System.identityHashCode(r), ...);
		...
        //提交事务
		mService.getLifecycleManager().scheduleTransaction(clientTransaction); //(3) 将事务提交给了ClientLifecycleManager
    }
    ...
}
         
//ClientLifecycleManager.java#scheduleTransaction
class ClientLifecycleManager {    
    ...
    /**
    * 调度一个事务,该事务可能由多个回调和一个生命周期请求组成
    */
    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule(); //* 核心方法
        if (!(client instanceof Binder)) {
            // If client is not an instance of Binder - it's a remote call and at this point it is
            // safe to recycle the object. All objects used for local calls will be recycled after
            // the transaction is executed on client in ActivityThread.
            transaction.recycle();
        }
    }
    ...
}
      
//ClientTransaction.java#schedule
public class ClientTransaction implements Parcelable, ObjectPoolItem {
    ...
    private IApplicationThread mClient;
    ...
    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this); //(4)
    }
    ...
}
   

① 这里创建了ClinetTransaction, ActivityThread创建Activity需要一个用来启动Activity事物的对象,也就是ClinetTransaction,ClinetTransaction就是用来启动我们的Activity的。(ClientTransaction的obtain方法传入了ApplicationtThread,说明Activity在该obtain方法里面完成创建)

② 这里添加了回调,并把LaunchActivityItem传到了ClientTransaction内。

③ 将Activity的启动事务提交给了ClientLifecycleManager。

④ 这里调用了ApplicationThread代理对象的scheduleTransaction方法,也就是从系统进程回到了APP进程。


我们来看看ApplicationThread是如何传入ClientTransaction的。

//ActivityTaskSupervisor.java#realStartActivityLocked
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
                                boolean andResume, boolean checkConfig) throws RemoteException {
    ...
	final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token);
    ...
}

//ClientTransaction.java#obtain
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
     ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
     if (instance == null) {
         instance = new ClientTransaction();
     }
     instance.mClient = client;
     instance.mActivityToken = activityToken;

     return instance;
 }
附录:ActivityTaskManagerService的启动

可以在SystemService中看到ActivityTaskManagerService的启动,这个了解一下就可以了。

//SystemServer.java
...
public static void main(String[] args) {new SystemServer().run();}
...
private void run() {
    ...
    startBootstrapServices(t);
    startCoreServices(t);
    startOtherServices(t);
    startApexServices(t);
    ...
}
...
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    ...
    ActivityTaskManagerService atm = mSystemServiceManager.startService(
        ActivityTaskManagerService.Lifecycle.class).getService();
    mActivityManagerService = ActivityManagerService.Lifecycle.startService(mSystemServiceManager, atm);
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);
    mWindowManagerGlobalLock = atm.getGlobalLock();
    ...
}
2. 创建Activity实例
//ActivityThread$ApplicationThread.java#scheduleTransaction
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}
    
//ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler
        implements ActivityThreadInternal {
	...
}
                                      
//ClientTransactionHandler.java
public abstract class ClientTransactionHandler {
   	void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
}

//ActivityThread$H.java#handleMessage
public final class ActivityThread extends ClientTransactionHandler
        implements ActivityThreadInternal {
    private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); //*
    ...
	class H extends Handler {
        public void handleMessage(Message msg) {
            ...
            case EXECUTE_TRANSACTION:
                final ClientTransaction transaction = (ClientTransaction) msg.obj;
                mTransactionExecutor.execute(transaction); //mTransactionExecutor是执行事务的对象
                if (isSystem()) {
                    transaction.recycle();
                }
                break;
            ...
        }
    }
}

//TransactionExecutor.java#execute
public void execute(ClientTransaction transaction) {
	...
	executeCallbacks(transaction);    
	executeLifecycleState(transaction);
    ...
}

//TransactionExecutor.java#executeCallbacks
private ClientTransactionHandler mTransactionHandler; //(1)
...
public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); //获取transaction的所有回调类
    ... 
    //遍历事务管理器中的所有窗口请求对象
    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i); //*
        ...
        item.execute(mTransactionHandler, token, mPendingActions); //(2) 进行窗体创建请求
        item.postExecute(mTransactionHandler, token, mPendingActions);
    }
    ...
}

//ClientTransactionItem.java
public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable {
}

② item的execute方法有个mTransactionHandler参数是ClientTransactionHandler类型①的成员变量,而ClientTransactionHandler则是ActivityThread的父类,也就是说这里传入execute的是ActivityThread。


在TransactionExecutor.java#executeCallbacks方法中,遍历了ClientTransaction所有的回调对象,也就是ClientTransactionItem的实例,然后调用了它们的execute方法,来进行窗口创建请求。

而这些ClientTransactionItem实例是在哪里添加进来的?之前在3-1-(3)-ActivityTaskSupervisor.java#realStartActivityLocked方法中有提到,添加进来的就是LaunchActivityItem,而LaunchActivityItem是ClientTransactionItem的实现类。

//LaunchActivityItem.java#execute
public void execute(ClientTransactionHandler client, IBinder token,
                    PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    //创建一个ActivityClientRecord对象,用于Activity的实例化
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
                client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
                mTaskFragmentToken);
    //将创建的ActivityClientRecord回调给ActivityThread
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}


//ActivityThread.java#handleLaunchActivity
public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
    ...
    //根据传过来的ActivityClientRecord创建一个Activity
	final Activity a = performLaunchActivity(r, customIntent);
    ...
}

//ActivityThread.java#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   	...
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); //创建Activity
    ...
}
    
    
//Instrumentation.java#newActivity
public Activity newActivity(ClassLoader cl, String className, Intent intent)
    throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    //通过意图获取目标Activity的包名,用来获取Activity工厂
    String pkg = intent != null && intent.getComponent() != null
        ? intent.getComponent().getPackageName() : null; 
    这里获取AppComponentFactory实例后,创建了Activity
    return getFactory(pkg).instantiateActivity(cl, className, intent); //(1)
}
    
//AppComponentFactory.java
public class AppComponentFactory {
    ...
    public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Activity) cl.loadClass(className).newInstance(); //类加载器创建Activfity实例
    }
    ...
}

① 详情见本节附录


Activity的启动会通过Intent拿到目的地Activity的全类名,然后根据类加载器来进行实例化。

附录:AppComponentFactory
public class AppComponentFactory {
   public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl,
            @NonNull ApplicationInfo aInfo) {...}
	
    public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,@NonNull String className) { ...}
    
    public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent) {...}
    
    public @NonNull BroadcastReceiver instantiateReceiver(@NonNull ClassLoader cl,
                                                          @NonNull String className, @Nullable Intent intent) {...}

    public @NonNull Service instantiateService(@NonNull ClassLoader cl,
                                               @NonNull String className, @Nullable Intent intent){...}
    
    public @NonNull ContentProvider instantiateProvider(@NonNull ClassLoader cl,
                                                          @NonNull String className) {,,,}
    
    public static final AppComponentFactory DEFAULT = new AppComponentFactory();
}

可以看到所有的组件都是通过AppComponentFactory创建的。

接下来看看Instrumentation是怎么获取AppComponentFactory的。

//Instrumentation.java#getFactory
private ActivityThread mThread = null;
...
private AppComponentFactory getFactory(String pkg) {
    if (pkg == null) { //如果没有Intent携带的全类名,就用默认工厂对象
        Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
        return AppComponentFactory.DEFAULT;
    }
    if (mThread == null) {        //如果没有ActivityThread,也用默认工厂对象
        Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
              + " disabling AppComponentFactory", new Throwable());
        return AppComponentFactory.DEFAULT; 
    }
    LoadedApk apk = mThread.peekPackageInfo(pkg, true); //根据包名获取当前apk对应的LoadedApk对象
    // This is in the case of starting up "android".
    if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
    //获取由manifest文件标签的android:appComponentFactory属性指定的工厂,也就是可以自定义应用组件实例化的工厂
    return apk.getAppFactory();
}

//ActivityThread.java#peekPackageInfo
//这里缓存了不同APK对应的LoadedApk对象,也就是可以通过这些map来实现APP间的远程通讯
final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages = new ArrayMap<>();
...
public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
    //ActivityThead通过弱引用的方式缓存不同APK的LoadedApk对象,这里根据APK的包名取出对应的LoaderApk
    synchronized (mResourcesManager) {
        WeakReference<LoadedApk> ref;
        if (includeCode) {
            ref = mPackages.get(packageName);
        } else {
            ref = mResourcePackages.get(packageName);
        }
        return ref != null ? ref.get() : null;
    }
}

//LoadedApk.java#createAppFactory
private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
    if (mIncludeCode && appInfo.appComponentFactory != null && cl != null) {
        try {
            //如果清单文件指定了appComponentFactory就通过类加载器创建该对象,否则返回默认的AppComponentFactory对象
            return (AppComponentFactory)
                cl.loadClass(appInfo.appComponentFactory).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            Slog.e(TAG, "Unable to instantiate appComponentFactory", e);
        }
    }
    return AppComponentFactory.DEFAULT;
}    
3. 启动Activity

现在Activity已经创建,我们回到创建Activity的创建的地方,看看Activity创建后是如何启动的。

//ActivityThread.java#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    ...
    activity = mInstrumentation.newAct\ivity(cl, component.getClassName(), r.intent); //创建Activity
    ...
    activity.attach(appContext, **); //调用Activity的attachBaseContext方法
    ...
    //调用Activity的onCreate方法
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    ...
}

//Instrumentation.java#callActivityOnCreate
public void callActivityOnCreate(Activity activity, Bundle icicle,
                                 PersistableBundle persistentState) {
    prePerformCreate(activity);
    activity.performCreate(icicle, persistentState);
    postPerformCreate(activity);
}

//Activity.java#performCreate
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    ...
    if (persistentState != null) {
        onCreate(icicle, persistentState);
    } else {
        onCreate(icicle);
    }
    ...
}

Activity启动完成后,接下来就是启动UI页面了。

二、UI绘制流程

1、Activity加载XML文件的过程

1. PhoneWindow的初始化
(1) 创建PhoneWindow

上一小节,我们已经追踪到了Activity的onCreate方法,这UI绘制流程的入口呼之欲出,也就是setContentView方法了。

public class MainActivity extends Activity {

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

不妨让我们看看setContentView做了什么。

//Activity.java#setContentView
public void setContentView(@LayoutRes int layoutResID) {
    //实际上调用的是PhoneWindow.setContentView()方法 --> PhoneWindow是window的唯一实现类
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

//Activity.java#getWindow
private Window mWindow;
...
public Window getWindow() {
    return mWindow;
}

//Window.java#setContentView
public abstract class Window {
    ...
    public abstract void setContentView(View view);
    ...
}

//Activity.java#mWindow
final void attach(Context context, ...) {
    attachBaseContext(context);
    ...
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    ...
}  

可以看到mWindow其实是PhoneWindow(该类其实也是Window的唯一实现类)对象,也就是Activity#setContentView,后面调用的其实是PhoneWindow#setContentView。

番外话:从Activity#attach可以看出,执行attachBaseContext方法时,mWIndow还未实例化,所以attachBaseContext中不能执行setContentView方法

(2) PhoneWindow的重要属性——mDecor和mContentParent

在追踪PhoneWindow#setContentView之前,先来了解一下PhoneWindow的几个重要的属性。

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    //这是窗口的顶级视图,它可以包含所有的窗口修饰	
    private DecorView mDecor; //(1)
    
    /**
    * 布局容器
    * 这是放置窗口内容的视图。它要么是mDecor本身,要么是mDecor的内容所在的子级。
    */
    ViewGroup mContentParent; //(2)
}

① DecorView是顶层的视图,是Activity最外层的View。

② mContentParent要么是mDecor,要么是mDecor的子View。


Framework学习之路(一)—— UI绘制深入源码分析_第1张图片

2-1-1-2 图片来自网图
(3) mDecor和mContentParent属性的初始化

接下来看看PhoneWindow#setContentView做了什么?

//PhoneWindow.java#setContentView
public void setContentView(int layoutResID) {
    //mContentParent肯定会为空  因为我们当前还是窗体初始化
    if (mContentParent == null) {
        //初始化顶层布局
        installDecor(); //这里做了两件事,分别是mDecor的初始化和mContentParent的初始化
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
    ...
}

//PhoneWindow.java#installDecor
private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
        //初始化mDecor
        mDecor = generateDecor(-1); //创建mDecor
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        //通过mDecor初始化ContentParent
        mContentParent = generateLayout(mDecor);
        ...
    }
}
[1] 初始化mDecor属性

先看一下mDecor初始化时,PhoneWindow.java#generateDecor方法做了什么。

//PhoneWindow.java#generateDecor
protected DecorView generateDecor(int featureId) {
    //系统进程没有应用程序上下文,在这种情况下,我们需要直接使用我们拥有的上下文。否则,我们需要应用程序上下文,因此我们不会紧紧抓住活动。
    Context context;
    if (mUseDecorContext) {
        Context applicationContext = getContext().getApplicationContext();
        if (applicationContext == null) {
            context = getContext();
        } else {
            context = new DecorContext(applicationContext, this);
            if (mTheme != -1) {
                context.setTheme(mTheme);
            }
        }
    } else {
        context = getContext();
    }
    return new DecorView(context, featureId, this, getAttributes()); //创建DecorView对象
}

PhoneWindow.java#generateDecor只是简单new了一个DecorView对象。

[2] 初始化mContentParent属性

接着看ContentParent初始化时,PhoneWindow.java#generateLayout方法做了什么。

//PhoneWindow.java#generateLayout
protected ViewGroup generateLayout(DecorView decor) {
    //获取应用当前主题中的数据,比如是否全屏、悬浮、有无title等
    TypedArray a = getWindowStyle();
    ...
    //获取窗体布局属性    
    WindowManager.LayoutParams params = getAttributes();
    ...
    //给窗体进行装饰
        
	int layoutResource; //资源ID,他会根据不同的主题加载对应的XML文件
    
    int features = getLocalFeatures();
    //加载系统布局 判断到底是加载哪个系统的布局
    if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
        if (mIsFloating) {
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_title_icons;
        }
    } ...  else {
        layoutResource = R.layout.screen_simple; //(1)
    }

    mDecor.startChanging();
    //将加载到的基础布局添加到了最外层View,也就是mDecor里面。
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);   //(2)
    //通过系统content资源ID去加载实例化这个控件
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); //(3)
    if (contentParent == null) {
        //如果contentParent为null,就会抛出异常。这点毋庸置疑,它肯定不能为空
        throw new RuntimeException("Window couldn't find content container view");
    }
    ... 
    return contentParent;  //这里返回了ContentView
}

//Window.java#ID_ANDROID_CONTENT
/**
* XML布局文件中主布局应具有的ID
*/
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content; //(4)

① R.layout.screen_simple是最常见的布局,详见本节附录一。

② DecorView通过onResourcesLoaded方法添加layoutResource基础布局,详见本节附录二。

③④ R.id.content,就是附录一中根布局的FrameLayout的id,也就是说③这里拿到了ContentView,并赋值给contentParent局部变量。


我们回到PhoneWindow,在2-1-1-(2)中,我们提到过mContentParent是mDecor,要么是mDecor的子View。通过上面的跟踪,发现我们现在得到的mContentParent正是根布局的ContentView,也就是mDecor的子View。

//PhoneWindow.java#installDecor
ViewGroup mContentParent;
...
private void installDecor() {    
    if (mContentParent == null) {
        //通过mDecor初始化ContentParent
        mContentParent = generateLayout(mDecor);
        ...
    }
}

这时候PhoneWindow.java#installDecor方法的两个初始化操作已经完成了,mDecor和mContentPare都完成了初始化。

附录一:常见的根布局——screen_simple.xml

下面就是最常见的根布局XML文件的代码。



    
    

R.id.action_mode_bar_stub待会再提。

R.id.content是状态栏下的页面,也就是手机显示屏上的主体内容。它是Activity#setContentView对应的ContentView,一般情况下,我们自己写的布局文件真正的父布局就是ContentView。

action_mode_bar_stub和content分别对应图片2-1-1-2中的TitleView和ContentView,不过还是有些出入,所以笔者又找了一张更合适的图片2-1-1-a。

Framework学习之路(一)—— UI绘制深入源码分析_第2张图片
2-1-1-a 图片来自网图

接下来特别说说R.id.action_mode_bar_stub,之所以特别说,是因为我在追踪R.id.action_mode_bar_stub的时候绕了个弯路,下面讲讲踩坑过程。

R.id.action_mode_bar_stub之前以为是状态栏,直到追踪AppCompatActivity的时候(详见2-2),发现有两个R.id.action_mode_bar_stub,难道AppCompatActivity还能有两个状态栏不成???

绝对不可能!!!

于是按惯性思维,认为AppCompatActivity的R.id.action_mode_bar_stub替换了原来的R.id.action_mode_bar_stub,这样的话它替换的逻辑应该类似ContentView,那么它必然是在布局初始化的时候发生的,思路有了之后,以PhoneWindow.java#generateLayout和AppCompatDelegateImpl.java#ensureSubDecor方法为核心追踪了半天,结果当然是追踪了个寂寞。

干脆用"R.id.action_mode_bar_stub"来进行查找,很快我在DecorView找到了它。

//DecorView.java#createStandaloneActionMode
private ActionBarContextView mPrimaryActionModeView;
...
private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
    ...
    ViewStub stub = findViewById(R.id.action_mode_bar_stub);
    if (stub != null) {
        mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
        mPrimaryActionModePopup = null;
    }
    ...
}

ActionBarContextView?这是和标题栏有关?再看一下调用的方法名createStandaloneActionMode,创建ActionMode?

于是我有了一种不祥的预感,反向追踪一下代码。

//DecorView.java#createStandaloneActionMode
private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
    ...
}

//DecorView.java#createActionMode
private ActionMode createActionMode(
    ....
    return createStandaloneActionMode(callback);
    ...
}
     
//DecorView.java#startActionMode
private ActionMode startActionMode(
            View originatingView, ActionMode.Callback callback, int type) {
    ...
    mode = createActionMode(type, wrappedCallback, originatingView);
    ...
}

可以看到在启动ActionMode的时候,膨胀了action_mode_bar_stub。

再回忆一下id的名字action_mode_bar_stub和它的类型ViewStub(状态栏还能不可见?)。

这时候该抽自己一巴掌,action_mode_bar_stub和状态栏不能说一模一样,只能说毫无关系。

那么状态栏究竟是谁?

这时候为了避免干扰,设置一下无标题主题,然后运行了一下程序。

打开SDK->tools->bin->uiautomatorviewer.bat,终于看到了正正经经的状态栏R.id.statusBarBackground(如图2-1-1-a2)。

为了更清晰的和action_mode_bar_stub进行对比,又打开了SDK->tools->monitor.bat->HierarchyView(如同2-1-1-a3)。

Framework学习之路(一)—— UI绘制深入源码分析_第3张图片
2-1-1-a2
Framework学习之路(一)—— UI绘制深入源码分析_第4张图片
2-1-1-a3

在DecorView中可以找到ColorViewState类型的mStatusColorViewState变量,它持有状态栏,也持有状态栏的状态和资源ID等属性。

//DecorView.java#mStatusColorViewState
public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
    new ColorViewAttributes(FLAG_TRANSLUCENT_STATUS,
                            Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
                            Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
                            com.android.internal.R.id.statusBarBackground, ITYPE_STATUS_BAR);
...
private final ColorViewState mStatusColorViewState =
    new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);

//DecorView$ColorViewState.java
private static class ColorViewState {
    View view = null;
    int targetVisibility = View.INVISIBLE;
    boolean present = false;
    boolean visible;
    int color;

    final ColorViewAttributes attributes;

    ColorViewState(ColorViewAttributes attributes) {
        this.attributes = attributes;
    }
}

//DecorView$ColorViewAttributes.java
public static class ColorViewAttributes {
    final int id;
    final int translucentFlag;
    final int verticalGravity;
    final int horizontalGravity;
    final int seascapeGravity;
    final String transitionName;
    final @InternalInsetsType int insetsType;

    private ColorViewAttributes(int translucentFlag, int verticalGravity, int horizontalGravity,
                                int seascapeGravity, String transitionName, int id,
                                @InternalInsetsType int insetsType) {
        this.id = id;
        this.translucentFlag = translucentFlag;
        this.verticalGravity = verticalGravity;
        this.horizontalGravity = horizontalGravity;
        this.seascapeGravity = seascapeGravity;
        this.transitionName = transitionName;
        this.insetsType = insetsType;
    }

    public boolean isPresent(boolean requestedVisible, int windowFlags, boolean force) {
        return requestedVisible
            && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || force);
    }

    public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
        return present
            && (color & Color.BLACK) != 0
            && ((windowFlags & translucentFlag) == 0  || force);
    }

    public boolean isVisible(InsetsState state, int color, int windowFlags, boolean force) {
        final boolean present = isPresent(state.getSource(insetsType).isVisible(), windowFlags,
                                          force);
        return isVisible(present, color, windowFlags, force);
    }
}

接下来看看状态栏的初始化过程。

//ActivityThread.java#handleStartActivity
public void handleStartActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, ActivityOptions activityOptions) {
    ...
    mInstrumentation.callActivityOnPostCreate(activity, ...);
    ...
}

//Instrumentation.java#callActivityOnPostCreate
public void callActivityOnPostCreate(@NonNull Activity activity,
                                     @Nullable Bundle savedInstanceState) {
    activity.onPostCreate(savedInstanceState);
}

//Activity.java#onPostCreate
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
    if (!isChild()) {
        mTitleReady = true;
        onTitleChanged(getTitle(), getTitleColor());
    }

    mCalled = true;

    notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_START);
}

//Activity.java#setTitle
protected void onTitleChanged(CharSequence title, int color) {
    if (mTitleReady) {
        final Window win = getWindow();
        if (win != null) {
            win.setTitle(title);
            if (color != 0) {
                win.setTitleColor(color);
            }
        }
        if (mActionBar != null) {
            mActionBar.setWindowTitle(title);
        }
    }
}

//PhoneWindow.java#setTitle
public void setTitle(CharSequence title) {
    setTitle(title, true);
}

public void setTitle(CharSequence title, boolean updateAccessibilityTitle) {
    if (mTitleView != null) {
        mTitleView.setText(title);
    } else if (mDecorContentParent != null) {
        mDecorContentParent.setWindowTitle(title);
    }
    mTitle = title;
    if (updateAccessibilityTitle) {
        WindowManager.LayoutParams params = getAttributes();
        if (!TextUtils.equals(title, params.accessibilityTitle)) {
            params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
            if (mDecor != null) {
                // ViewRootImpl will make sure the change propagates to WindowManagerService
                ViewRootImpl vr = mDecor.getViewRootImpl();
                if (vr != null) {
                    vr.onWindowTitleChanged();
                }
            }
            dispatchWindowAttributesChanged(getAttributes());
        }
    }
}

//PhoneWindow.java#dispatchWindowAttributesChanged
protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
    super.dispatchWindowAttributesChanged(attrs);
    if (mDecor != null) {
        mDecor.updateColorViews(null /* insets */, true /* animate */);
    }
}

//DecorView.java#updateColorViews
WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
    ...
    updateColorViewInt(mStatusColorViewState, statusBarColor, 0,
                       mLastTopInset, false /* matchVertical */, statusBarNeedsLeftInset,
                       statusBarSideInset, animate && !disallowAnimate,
                       mForceWindowDrawsBarBackgrounds, controller);
    ...
}


//DecorView.java#updateColorViewInt
private void updateColorViewInt(final ColorViewState state, int color, int dividerColor,
                                int size, boolean verticalBar, boolean seascape, int sideMargin, boolean animate,
                                boolean force, WindowInsetsController controller) {
    ...
    if (view == null) {
        if (showView) {
            state.view = view = new View(mContext); //初始化状态栏对应的View
            setColor(view, color, dividerColor, verticalBar, seascape);
            view.setTransitionName(state.attributes.transitionName);
            view.setId(state.attributes.id); //状态栏的ID
            visibilityChanged = true;
            view.setVisibility(INVISIBLE);
            state.targetVisibility = VISIBLE;
            ...            
            addView(view, lp); //将状态栏添加到DecorView中
            ...
        }
    }
}     

到这里状态栏就添加到了布局中。

最后,推荐一篇写的很好的博客:探索 Android View 绘制流程。

附录二:DecorVIew添加RootView

下面是DecorView添加基础布局的代码。

//DecorView.java#onResourcesLoaded
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
 	...
    mDecorCaptionView = createDecorCaptionView(inflater);
    //把传过来的根布局layoutResource进行解析并渲染
    final View root = inflater.inflate(layoutResource, null); //通过inflate解析根布局layoutResource
    if (mDecorCaptionView != null) {
        if (mDecorCaptionView.getParent() == null) {
            addView(mDecorCaptionView,
                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mDecorCaptionView.addView(root,
                                  new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
    } else {
        //将其放在颜色视图下方
        addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); //将rootView添加到进DecorView中并填满屏幕
    }
    mContentRoot = (ViewGroup) root;
    initializeElevation();
}
2. 加载自定义布局

根布局加载完后,就开始来加载我们自己定义的布局了,例如加载activity_main.xml。

//PhoneWindow.java#setContentView
private LayoutInflater mLayoutInflater;
...
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        //初始化mDecor和mContentParent
        installDecor(); 
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
		...
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        ...
    } else {
        //去加载自己定义的layout
        mLayoutInflater.inflate(layoutResID, mContentParent); //传入R.layout.activity_main和ContentView
    }   
    ...
}

//LayoutInflater.java#inflate
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
 	...
    XmlResourceParser parser = res.getLayout(resource); //解析activity_main.xml布局文件
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        ...
        root.addView(temp, params); //将R.layout.activity_main添加到ContentView中
        ...
    }
}

可以看到activity_main.xml已经加载到了Activity里面。

2、AppCompatActivity加载XML文件的过程

上一小节已经看过了Activity加载布局文件的过程,但是开发中,我们遇到AppCompatActivity的情况显然更多,接下来就看看AppCompatActivity和Activity加载布局文件的过程有何不同。

1. 初始化PhoneWIndow的mDecor和mDecorContentParent属性
public class MainActivity extends AppCompatActivity {

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

//AppCompatActivity.java#setContentView
public void setContentView(@LayoutRes int layoutResID) {
    initViewTreeOwners();
    getDelegate().setContentView(layoutResID);
}

//AppCompatActivity.java#getDelegate
private AppCompatDelegate mDelegate;
...
public AppCompatDelegate getDelegate() {
    if (mDelegate == null) {
        mDelegate = AppCompatDelegate.create(this, this); //当mDelegate为null时,创建mDelegate实例并返回
    }
    return mDelegate;
}

//AppCompatDelegate.java#create
public abstract class AppCompatDelegate {
    ...
    public static AppCompatDelegate create(@NonNull Activity activity,
                                           @Nullable AppCompatCallback callback) {
        return new AppCompatDelegateImpl(activity, callback); //(1)
    }
    ...
}

看到这里发现AppCompatActivityt并不是通过PhoneWindow设置布局的,而是通过AppCompatDelegate的实现类AppCompatDelegateImpl。

接下来我们来看看AppCompatDelegateImpl.java#setContentView是如何加载基础布局的。

//AppCompatDelegateImpl.java#setContentView
public void setContentView(View v) {
    ensureSubDecor(); //初始化根布局
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); //获取ContentView
    contentParent.removeAllViews();
    contentParent.addView(v);
    mAppCompatWindowCallback.getWrapped().onContentChanged();
}

//AppCompatDelegateImpl.java#ensureSubDecor
ViewGroup mSubDecor; //mSubDecor可以对标Activity的mDecor
,,,
private void ensureSubDecor() {   
    if (!mSubDecorInstalled) {
        //mSubDecor的初始化
        mSubDecor = createSubDecor();
        ...
		onSubDecorInstalled(mSubDecor);
        ...
    }
}

//AppCompatDelegateImpl.java#createSubDecor
private ViewGroup createSubDecor() {   
    ...
    mWindow.getDecorView();
    ...        
}

//PhoneWindow.java#getDecorView
public final @NonNull View getDecorView() {
    if (mDecor == null || mForceDecorInstall) {
        installDecor(); //初始化mDecor和mDecorContentParent
    }
    return mDecor;
}

我们看到AppCompatDelegateImpl也调用了PhoneWindow#installDecor方法来加载基础布局。

不过AppCompatDelegateImpl并没有直接使用installDecor的结果,而是在加载基础布局后,又做了一些操作。

我们继续看AppCompatDelegateImpl#createSubDecor方法。

2. 初始化AppCompatDelegateImpl的mSubDecor属性
//AppCompatDelegateImpl.java#createSubDecor
private ViewGroup createSubDecor() {
    //获取当前应用主题中的数据,根据主题加载对应的xml文件,然后赋值给mSubDecor
    TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
    ...
    mWindow.getDecorView(); //用和Activity的方式同样的方式加载基础布局
   
    final LayoutInflater inflater = LayoutInflater.from(mContext);
    ViewGroup subDecor = null;
    
    if (!mWindowNoTitle) {
        if (mIsFloating) {
            //如果我们是浮动的,请膨胀对话框标题装饰
            subDecor = (ViewGroup) inflater.inflate(
                R.layout.abc_dialog_title_material, null);

            //浮动窗口永远不能有操作栏,重置标志
            mHasActionBar = mOverlayActionBar = false;
        } else if (mHasActionBar) {
            ...
            //现在使用主题上下文膨胀视图并将其设置为内容视图
            subDecor = (ViewGroup) LayoutInflater.from(themedContext)
                        .inflate(R.layout.abc_screen_toolbar, null);
            ...
        } 
    } else {
            if (mOverlayActionMode) {
                subDecor = (ViewGroup) inflater.inflate(
                    R.layout.abc_screen_simple_overlay_action_mode, null);
            } else {
                subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null); //(1)
            }
        }
    }
    
    if (subDecor == null) {
        //如果subDecor为null,则抛出异常
        throw new IllegalArgumentException(...);
    }
    
    ...
    return subDecor;
}

①这里选择一个简单的xml做介绍,详见本节附录一


我们看到在PhoneWindow加载了基础布局后,进行了subDecor的创建,并将subDecor返回,单看这些,subDecor和AppCompatActivity并没有关联上。

其实在subDecor创建之后,AppCompatDelegateImpl#createSubDecor还对subDecor做了一些操作,操作完成后才返回subDecor。

我们来看看AppCompatDelegateImpl#createSubDecor在subDecor创建成功之后做了什么?

//AppCompatDelegateImpl.java#createSubDecor
private ViewGroup createSubDecor() {
    ...
	subDecor = ...;  //创建subDecor
    ...   
    final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
        R.id.action_bar_activity_content); //(1)

    final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content); //(2)
    
    if (windowContentView != null) {
        //可能已经将视图添加到窗口的内容视图中,因此我们需要将它们迁移到我们的内容视图中
        //------------ (3) ---------------
        while (windowContentView.getChildCount() > 0) {
            final View child = windowContentView.getChildAt(0);
            windowContentView.removeViewAt(0);
            contentView.addView(child);
        }

        //更改我们的内容 FrameLayout 以使用android.R.id.content id.对片段有用。
        //------------ (4) ---------------
        windowContentView.setId(View.NO_ID);
        contentView.setId(android.R.id.content);

        //装饰内容可能有一个前景可绘制对象集(windowContentOvelay)。删除它,因为我们自己处理它
        if (windowContentView instanceof FrameLayout) {
            ((FrameLayout) windowContentView).setForeground(null);(5)
        }
    }

    //现在使用装饰设置窗口的内容视图
    mWindow.setContentView(subDecor); //(6)
   	...
    return subDecor;
}

//View.javaNO_ID
/**
* 用于标记没有 ID 的视图。
*/
public static final int NO_ID = -1; //(7)

① 获取subDecor加载的布局文件的ContentView,详见本节附录一。

② 获取当前PhoneWindow加载的基础布局文件中的ContentView。

③ 这段代码将PhoneWindow的ContentView中的所有子控件全部转移到subDecor中,转移后当前PhoneWIndow内的ContentView被清空。(这里注意,当前还未加载R.layout.activity_main,所以PhoneWindowd的ContentView可能是个空布局,这时就没必要转移,即直接跳过while循环。)

④ 这里进行了移花接木,将windowContentView的id设置为View.NO_ID(删除了id,见⑦),再将contentView的ID设为android.R.id.content,完成了id的替换,这时候通过findViewById(R.id.content)找到的就不是原来的windowContentView,而是subDecor的contentView,当然这里还差一个将subDecor绑定到PhoneWindow中的操作,这时候到步骤⑥了。

⑤ 设置windowContentView的setForeground为null,也就是windowContentView跳过绘制过程,这时没有id有无法绘制的windowContentView相当于一个空View。

⑥ 将subDecor绑定到PhoneWindow。


我们看看subDecor是如何绑定到PhoneWindow上的?

//AppCompatDelegateImpl.java#createSubDecor
private ViewGroup createSubDecor() {
    ...
	mWindow.setContentView(subDecor);
    ...
}

//PhoneWindow.java#setContentView
public void setContentView(View view) {
	setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}

//PhoneWindow.java#setContentView
public void setContentView(View view, ViewGroup.LayoutParams params) {
 	...
	mContentParent.addView(view, params); 
    ...
}

我们看到这时候subDecor就加到了原先的ContentView下面,现在的根布局结构如图:

Framework学习之路(一)—— UI绘制深入源码分析_第5张图片
图2-2
3.加载自定义布局

这时候我们的AppCompatDelegateImpl#createSubDecor方法就看得差不多了,我们接着回到AppCompatDelegateImpl#ensureSubDecor。

//AppCompatDelegateImpl.java#ensureSubDecor
private void ensureSubDecor() {
     if (!mSubDecorInstalled) {
         mSubDecor = createSubDecor();
         ...
         onSubDecorInstalled(mSubDecor);
         mSubDecorInstalled = true;
         ...
     }
}

//AppCompatDelegateImpl.java#onSubDecorInstalled
void onSubDecorInstalled(ViewGroup subDecor) {}

这里有个onSubDecorInstalled方法,他是一个空方法,该方法主要用来重写的,一般没有特殊需求,我们不会重写它。

调用完onSubDecorInstalled方法,mSubDecorInstalled就被设置为true了,这时候ensureSubDecor方法再被调用就会直接被跳过。

从名字也可以看出来,ensureSubDecor方法是为了确保subDecor已经初始化,也就是说很多必须使用subDecor的地方,都需要调用该方法来保证subDecor已经初始化了。

class AppCompatDelegateImpl extends AppCompatDelegate
        implements MenuBuilder.Callback, LayoutInflater.Factory2 {
    public void onPostCreate(Bundle savedInstanceState) {
        // Make sure that the sub decor is installed
        ensureSubDecor();
    }
    ...
    private void initWindowDecorActionBar() {
        ensureSubDecor();
        ...
	}
    ...
    public <T extends View> T findViewById(@IdRes int id) {
        ensureSubDecor();
        return (T) mWindow.findViewById(id);
    }
    ...  
    @Override
    public void setContentView(View v) {
        ensureSubDecor();
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        contentParent.addView(v);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

    @Override
    public void setContentView(int resId) {
        ensureSubDecor();
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        LayoutInflater.from(mContext).inflate(resId, contentParent);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

    @Override
    public void setContentView(View v, ViewGroup.LayoutParams lp) {
        ensureSubDecor();
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        contentParent.addView(v, lp);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

    @Override
    public void addContentView(View v, ViewGroup.LayoutParams lp) {
        ensureSubDecor();
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.addView(v, lp);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }
}

我们重点看AppCompatDelegateImpl#setContentView方法,可以看到他把subDecor的ContentView的子空间全部清空了,然后将传进来的View添加到了ContentView里面,也就是让我们传进来的View替换了原先ContentView的布局。AppCompatDelegateImpl#addContentView的逻辑类似,只不过不会清空原先的View,也就是在原有的基础上加上了传进来的View。

我们回忆一下AppCompatDelegateImpl#setContentView的调用方。

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
	...
    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        initViewTreeOwners();
        getDelegate().setContentView(layoutResID);
    }

    @Override
    public void setContentView(View view) {
        initViewTreeOwners();
        getDelegate().setContentView(view);
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        initViewTreeOwners();
        getDelegate().setContentView(view, params);
    }

    @Override
    public void addContentView(View view, ViewGroup.LayoutParams params) {
        initViewTreeOwners();
        getDelegate().addContentView(view, params);
    }
	...
}

这时候我们又回到MainActivity了。

public class MainActivity extends AppCompatActivity {

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

再捋一下AppCompatActivity加载资源ID的路线。

//AppCompatActivity.java#setContentView
public void setContentView(@LayoutRes int layoutResID) {
        initViewTreeOwners();
        getDelegate().setContentView(layoutResID);
}

//AppCompatDelegateImpl.java#setContentView
public void setContentView(int resId) {
    ...
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    ...
}

//LayoutInflater#inflate
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

其实AppCompatActivity主要就是在Activity加载XML的基础上添加了SubDecor,其他的大差不差。

附录一:简单根布局abc_screen_simple.xml

<androidx.appcompat.widget.FitWindowsLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/action_bar_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:fitsSystemWindows="true">

    <androidx.appcompat.widget.ViewStubCompat
        android:id="@+id/action_mode_bar_stub"
        android:inflatedId="@+id/action_mode_bar"
        android:layout="@layout/abc_action_mode_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <include layout="@layout/abc_screen_content_include" />

androidx.appcompat.widget.FitWindowsLinearLayout>


<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <androidx.appcompat.widget.ContentFrameLayout
            android:id="@id/action_bar_activity_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:foregroundGravity="fill_horizontal|top"
            android:foreground="?android:attr/windowContentOverlay" />
merge>

3、UI绘制过程

现在XML已经加载好了,接下来谈谈UI具体的绘制过程,既然说到了绘制过程,那么肯定有一个生命周期是绕不开的也就是onResume。

我们先看看ActivityThread的handleResumeActivity方法。

(PS:这里笔者猜测ActivityThread#handleResumeActivity的调用方应该在TransactionExecutor.java#performLifecycleSequence,可以在上面的创建Activity实例小节中找到TransactionExecutor.java#executeCallbacks方法,不过之后的代码在小节中没有出现。可以自行依照executeCallbacks->cycleToPath->performLifecycleSequence的路径查找,该方法里面可以看到各种ActivityThread.java#handleXXXActivity生命周期方法的调用,笔者本来想要写入附录,但因为出现了很多疑问,所以暂且搁置,如果有机会,笔者会在了解过Activity整体的生命周期流程之后,再单独拿一篇出来讲讲Activity所有生命周期的流程。当然因为水平有限可能写的不好,这里只能恳请路过的大佬帮忙指点一二。)

//ActivityThread.java#handleResumeActivity
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {
    ...
    //待办事项 将 resumeArgs 推送到活动中以供考虑 跳过以下步骤进行双重恢复和 r.mFinish = true
    if (!performResumeActivity(r, finalStateRequest, reason)) { //这里会执行Activity的onResume方法
        return;
    }
    ...
    //获取Activity
	final Activity a = r.activity;
    ...    
    if (r.window == null && !a.mFinished && willBeVisible) {
        	//获取到Activity的PhoneWindow
            r.window = r.activity.getWindow();
			//获取到PhoneWindow的基础布局,也就是最外层的DecorView                                                            
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
			//获取到Activity的WindowManager对象                                                            
            ViewManager wm = a.getWindowManager();
			//获取到Activity的window的LayoutParams
            WindowManager.LayoutParams l = r.window.getAttributes();
			//把decorView从Activity记录类中拿出来交给Activity                                                            
            a.mDecor = decor;
			...
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                //通常,ViewRoot 使用 addView->ViewRootImpl#setView 中的活动设置回调。
                //如果我们要重用装饰视图,则必须通知视图根目录回调可能已更改。
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //调用绘制方法
                    wm.addView(decor, l); //* 重点
                } else {
                    //该活动将更早地获得此 {@link LayoutParams} 更改的回调。但是,届时不会设置装
                    //饰(在此方法中设置),因此不会执行任何操作。此调用可确保回调与装饰集一起发生。
                    a.onWindowAttributesChanged(l);
                }
            }
            ...
    }	
	...        
}

这里看完代码会发现Activity的onResume方法,其实是在UI绘制之前调用的,这点需要注意,一不小心就可能翻车。

关于这个坑,笔者再推荐一篇不错的博客:源码详细解析Activity生命周期onResume中Handler.Post(Runnable)和View.Post(Runnable)的UI效果差异原因

1. 调用Activity的onResume方法

接下来我们来看看Activity的onResume生命周期是如何被调用的。

//ActivityThread.java#handleResumeActivity
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {
    ...
    if (!performResumeActivity(r, finalStateRequest, reason)) { //这里会执行Activity的onResume方法
        return;
    }
}

//ActivityThread.java#performResumeActivity
public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
                                     String reason) {
    ...
    r.activity.performResume(r.startsNotResumed, reason);
    ...
}

//Activity.java#performResume
final void performResume(boolean followedByPause, String reason) {
    ...
    mInstrumentation.callActivityOnResume(this);
    ...
}

//Instrumentation.java#callActivityOnResume
public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    activity.onResume();
	...
}

现在我们Activity的onResume方法已经被调用了,接着就来看看Activity的显示流程。

(PS:这里performResumeActivity方法里面调用的不只是onResume方法,在此之前,如果Activity是重用的会先调用OnNewIntent方法,接着会判断Activity此前是否经历过onStop方法,如果有则会触发onRestart方法,然后调用onStart。这部分也会一并写到后面关于Activity生命周期流程的文章中。)

2. ViewRootImpl进行UI绘制的过程
(1) View绘制三大流程的入口

接下来我们来看看UI具体的绘制过程。

我们回到ActivityThread#handleResumeActivity方法,接着看看之ViewManager#addView方法是怎么来的。

//ActivityThread.java#handleResumeActivity
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {
    ...
    final Activity a = r.activity;
    ...
	ViewManager wm = a.getWindowManager();
    ...
    wm.addView(decor, l);
    ...
}

//Activity.java#getWindowManager
public WindowManager getWindowManager() {
    return mWindowManager;
}

//Activity.java#mWindowManager
private Window mWindow;
private WindowManager mWindowManager;
...
final void attach(Context context, ActivityThread aThread, ...) {
    ...
    mWindowManager = mWindow.getWindowManager();
    ...
}

//Window.java#getWindowManager
public WindowManager getWindowManager() {
    return mWindowManager;
}

//Window.java#mWindowManager
private WindowManager mWindowManager;
...
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.java#createLocalWindowManager
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
}

可以看到wm.addView方法中,wm变量其实是WindowManager的实现类WindowManagerImpl的对象。

看一下他的addView做了什么?

//WindowManagerImpl.java#addView 
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyTokens(params);
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                    mContext.getUserId());
} 

//WindowManagerGlobal.java#addView
@UnsupportedAppUsage
private final Object mLock = new Object();

@UnsupportedAppUsage
private final ArrayList<View> mViews = new ArrayList<View>();
@UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
@UnsupportedAppUsage
private final ArrayList<WindowManager.LayoutParams> mParams =
    new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();
...
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
    ...    
	ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        ...        
        if (windowlessSession == null) {
            root = new ViewRootImpl(view.getContext(), display);
        } else {
            root = new ViewRootImpl(view.getContext(), display, windowlessSession);
        }

        view.setLayoutParams(wparams);
        //这三个集合里面储存着应用中所有Activity的基础属性
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        //最后执行此操作,因为它会触发消息以开始执行操作
        try {
            root.setView(view, wparams, panelParentView, userId); //* 重点
        } catch (RuntimeException e) {
            //清理BadTokenException 或 InvalidDisplayException。
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }
    }
}

//ViewRootImpl.java#setView
View mView;
...
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
    ...
    mView = view; //将DecorView赋值给mView
    ...
    //安排第一个布局之前添加到窗口管理器,以确保我们在从系统接收任何其他事件之前进行重新布局。
    //和View的requestLayout方法类似,它会重新进行测量->布局->绘制的过程
    requestLayout();
    ...
    view.assignParent(this); //(1)
    ...
}

//ViewRootImpl.java#requestLayout
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        //检查线程
        checkThread(); // (2)
        mLayoutRequested = true;
        //调度遍历
        scheduleTraversals();
    }
} 

//ViewRootImpl.java#scheduleTraversals
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
...
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        //调用线程mTraversalRunnable
        mChoreographer.postCallback(
            Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

//ViewRootImpl$TraversalRunnable.java#run
final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        //执行调度
        doTraversal();
    }
}

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

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

        performTraversals(); //View绘制的测量、放置、绘制三大流程,就是在这里发生的

        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

//ViewRootImpl.java#performTraversals   
private void performTraversals() {
    //缓存mView,也就是DecorView,因为它在下面使用了很多...  
    final View host = mView;
    ...
    //询问Host想要多大 这里是绘制的开始
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ...
    performLayout(lp, mWidth, mHeight);
    ...
    performDraw()
    ...
}

①这里是将RootViewImpl添加为DecorView的父布局,详见附录一。

① 这里是线程检查,也就是检查是否为UI线程,详见附录二。


可以看到先测量、再布局、最后绘制,这个流程的顺序是由ViewRootImpl.java#performTraversals 方法确定的。

接下来我们就来具体看看这三个流程的调用。

(2) View绘制三大流程之onMeasure方法
//ViewRootImpl.java#performMeasure   
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
    if (mView == null) {
        return;
    }
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
    try {
        //调用DecorView的measure方法,这里会层层传递,测量整个Activity里面的所有View
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

 public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
     ...
     onMeasure(widthMeasureSpec, heightMeasureSpec);
     ...
 }
(3) View绘制三大流程之onLayout方法
//ViewRootImpl.java#performLayout
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
    ...
    final View host = mView; 
    ...
    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}

public void layout(int l, int t, int r, int b) {
    ...
    onLayout(changed, l, t, r, b);
    ...
}
(4) View绘制三大流程之onDraw方法
//ViewRootImpl.java#performDraw
private boolean performDraw() {
    ...
    boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);
    ...
}

//ViewRootImpl.java#draw
private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {
    ...
    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                      scalingRequired, dirty, surfaceInsets)) {
        return false;
    } 
    ...
}

//ViewRootImpl.java#drawSoftware
 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
     //使用软件渲染器绘制。
     final Canvas canvas;
     ...
     canvas = mSurface.lockCanvas(dirty);
     ...
     mView.draw(canvas);
     ...
 }

//ViewRootImpl.java#draw
public void draw(Canvas canvas) {
    ...
    onDraw(canvas);
    ,,,
}

附录一:将ViewRootImpl添加为DecorView的父布局

ViewRootImpl在setView中会被添加为根布局DecorView的父亲,下面看看添加的流程。

//ViewRootImpl.java# setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
                    int userId) {
    ...
    requestLayout();
    ...
    view.assignParent(this); //为DecorView分配父布局
    ...
}

//View.java#assignParent
protected ViewParent mParent;
...
/**
* 调用方负责在必要时调用 requestLayout。(这允许 addViewInLayout 不请求新布局。)
*/
void assignParent(ViewParent parent) {
    if (mParent == null) {
        mParent = parent;
    } else if (parent == null) {
        mParent = null;
    } else {
        throw new RuntimeException("view " + this + " being added, but"
                                   + " it already has a parent");
    }
}

/**
* 视图层次结构的顶部,在视图和窗口管理器之间实现所需的协议。这在很大程度上是WindowManagerGlobal的内部实现细节
*/
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
        AttachedSurfaceControl {
	...     
}

可以看到ViewRootImpl是整个布局结构的根节点,它管理整颗View树的测量、布局、绘制等过程,是View和WindowManger之间的沟通的桥梁。

值得一提的是,ViewRootImpl本身并不是View,只是实现了ViewParent接口,所以DecorView依旧是最顶层的View,是所有View的祖先节点。

附录二:UI线程检查

我们应该对UI线程都不陌生,那么UI线程究竟是怎么判断的?我们来看看ViewRootImpl.java的checkThread方法。

//ViewRootImpl.java#checkThread
void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
        "Only the original thread that created a view hierarchy can touch its views.");
    }
}

//ViewRootImpl.java#mThread
final Thread mThread;
...
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
            boolean useSfChoreographer) {
    ...
    mThread = Thread.currentThread();
    ...
}

可以看到UI线程,其实就是创建ViewRootImpl的线程,在回到上面讲的启动主线程的Looper。

这时候对比一下,就可以发现主线程是APP进程的第一个线程,而UI线程是创建ViewRootImpl的线程,也就是说两者不一定相同,这也就意味着在子线程修改UI,或者说让子线程成为UI线程,其实也是可行的。有兴趣的可以转到这里你不知道的,Android子线程中的UI操作
那么再换个思路,我们已经找到ViewRootImpl是在ActivityThead#onResume方法之后才初始化的,那么在此之前,UI不受ViewRootImpl控制,也就是说,不会有UI线程安全的问题,那么这就意味着我们在这段时间内是可以使用子线程修改UI的,当然这时候UI还没有绘制,相关内容可以转到这里震惊!Android子线程也能修改UI?

你可能感兴趣的:(Android,Framework学习之路,ui,android,java)