这一片文章主要讲View的绘制流程,具体指的是如何找的绘制入口。
具体该如何绘制将在下一篇文章内讲解。
基于API-23的源码讲解
part2:View的绘制流程
首先讲一下APP的启动过程:
1. 点击桌面APP图标时,Launcher的startActivity()方法,通过Binder通信,调用system_server进程中AMS服务的startActivity方法,发起启动请求
2. system_server进程接收到请求后,向Zygote进程发送创建进程的请求
3. Zygote进程fork出App进程,并执行ActivityThread的main方法,创建ActivityThread线程,初始化MainLooper,主线程Handler,同时初始化ApplicationThread用于和AMS通信交互
4. App进程,通过Binder向sytem_server进程发起attachApplication请求,这里实际上就是APP进程通过Binder调用sytem_server进程中AMS的attachApplication方法,上面我们已经分析过,AMS的attachApplication方法的作用是将ApplicationThread对象与AMS绑定
5. system_server进程在收到attachApplication的请求,进行一些准备工作后,再通过binder IPC向App进程发送handleBindApplication请求(初始化Application并调用onCreate方法)和scheduleLaunchActivity请求(创建启动Activity)
6. App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送BIND_APPLICATION和LAUNCH_ACTIVITY消息,这里注意的是AMS和主线程并不直接通信,而是AMS和主线程的内部类ApplicationThread通过Binder通信,ApplicationThread再和主线程通过Handler消息交互。 ( 这里猜测这样的设计意图可能是为了统一管理主线程与AMS的通信,并且不向AMS暴露主线程中的其他公开方法,大神可以来解析下)
7. 主线程在收到Message后,创建Application并调用onCreate方法,再通过反射机制创建目标Activity,并回调Activity.onCreate()等方法
8. 到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染后显示APP主界面
首先找到ActivityThread这个类的handleMessage方法:
ActivityThread:
public final class ActivityThread {
private class H extends Handler {
//省略...
public void handleMessage(Message msg) {
switch (msg.what) {
//关键代码:启动Activity会走到这里进行处理
case LAUNCH_ACTIVITY: {
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
//处理启动逻辑
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
break;
case RELAUNCH_ACTIVITY: {
//省略...
}
}
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
//关键代码
handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);
}
//省略...
}
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
ActivityClientRecord r = performResumeActivity(token, clearHide);//这段代码会回调onResume
if (r != null) {
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();//a表示Activity,回到Activity类里面找到getWindowManager方法
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);//关键代码wm是ViewManager对象,由a.getWindowManager()获取,代码跟踪后会发现到最后wm实际就是WindowManagerImpl对象
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
}
}
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) {
ActivityClientRecord r = mActivities.get(token);
if (r != null && !r.activity.mFinished) {
//省略...
//回调Activity的onResume方法
r.activity.performResume();
}
return r;
}
}
代码分析都在注释里面,这里简单说下过程:首先启动Activity之后回调到ActivityThread的handleMessage方法,走到case语句handleLaunchActivity(r, null);方法,然后继续走handleResumeActivity方法,在这个方法里面有一句关键代码: wm.addView(decor, l);这个wm是关键,这里先透漏下,其实跟踪到最后可以发现wm就是WindowManagerImpl对象。
接下来我们就一步步定位这个wm到底是什么?
ViewManager wm = a.getWindowManager();//a表示Activity,回到Activity类里面找到getWindowManager方法
Activity:
public class Activity {
/**
* 这个方法会在ActivityThread中handleResumeActivity方法被调用,返回WindowManager对象
* 而mWindowManager会在attach方法中被赋值
*/
public WindowManager getWindowManager() {
return mWindowManager;
}
/**
* mWindowManager被赋值的地方
* 实际就是调用了
* Window.getWindowManager-->PhoneWindow.getWindowManager(调用父类)-->Window.getWindowManager
*
*/
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) {
//省略...
//此处mWindow即PhoneWindow对象,PhoneWindow.getWindowManager方法实际是调用的父类,也就是Window.getWindowManager方法
//找到Window类中getWindowManager方法
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
}
代码分析:
走到了Activity的getWindowManager方法,然后发现返回mWindowManager,而mWindowManager对象是在attach方法中被赋值的mWindowManager = mWindow.getWindowManager(); 此处mWindow即PhoneWindow对象,PhoneWindow.getWindowManager方法实际是调用的父类,也就是Window.getWindowManager方法。
Window:
/**
* PhoneWindow是Window的唯一实现
*/
public abstract class Window {
/**
* 这个id是布局文件中FragmeLayout中的id
*/
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
/**
* 这个方法会在Activity中attach方法被调用返回,
* 而mWindowManager对象是在setWindowManager方法中被赋值
* @return
*/
public WindowManager getWindowManager() {
return mWindowManager;
}
/**
* mWindowManager被赋值的地方,最终发现其实是WindowManagerImpl对象
* 进而去找到WindowManagerImpl类中addView方法
*/
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
//省略...
//mWindowManager被赋值的地方
mWindowManager = ((WindowManagerImpl) wm).createLocalWindowManager(this);
}
}
最后在setWindowManager方法中发现mWindowManager实际就是WindowManagerImpl对象,因此我们找到WindowManagerImpl类,看addView方法:
WindowManagerImpl:
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mDisplay, parentWindow);
}
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//mGlobal是WindowManagerGlobal对象,所以继续跟进WindowManagerGlobal中addView方法
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
}
可以发现又调用了mGlobal.addView(view, params, mDisplay, mParentWindow);方法,mGlobal是WindowManagerGlobal对象,所以继续跟进WindowManagerGlobal中addView方法。
WindowManagerGlobal:
public final class WindowManagerGlobal {
/**
* @param view 实际就是DecorView
* @param params 布局参数
*/
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
synchronized (mLock) {
//省略...
root = new ViewRootImpl(view.getContext(), display);//新创建一个ViewRootImpl对象
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView);//将DecorView、LayoutParams进行关联,最后会走到ViewRootImpl.setView方法中
} catch (RuntimeException e) {
}
}
}
}
跟进到WindowManagerGlobal的addView方法里面,可以发现new了一个ViewRootImpl对象,并最终调用了setView方法。
跟进到ViewRootImpl类中找到setView方法:
ViewRootImpl:
class ViewRootImpl {
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
//省略...
//调用requestLayout方法
requestLayout();
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();//检查线程安全
mLayoutRequested = true;
scheduleTraversals();//关键代码
}
}
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//mTraversalRunnable是一个实现Runnable接口的任务
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();//调用doTraversal方法
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
//最后会调用performTraversals,而在这个方法里面就是View绘制的入口了
performTraversals();
}
}
/**
* 在performTraversales()方法里面就会有view绘制的三大步
*/
private void performTraversals() {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
performDraw();
}
}
来到ViewRootImp类里面,找到setView方法发现有requestLayout方法,接下来跟进到requestLayout方法里面,里面有checkThread方法判断是否在主线程,最后会一步步调用到performTraversales方法里面,在performTraversales()方法里面就会有view绘制的三大步。
总结:
当Activity创建之后,在ActivityThread.handleResumeActivity会通过wm.addView方法,这个wm的实现类就是WindowManagerImpl,addView的第一个参数decorView就是我们的顶层View,第二个参数表示我们顶层View的参数。
接着会调用WindowManagerGlobal.addView方法,在这个方法里面会创建ViewRootImpl对象,最后调用ViewRootImpl的setView方法,将decorView布局、属性进行关联。
关联之后就会在ViewRootImpl进行绘制,绘制开始会调用requestLayout方法-->scheduleTraversals方法-->doTraversal方法-->performTraversals方法。而真正执行绘制三大步骤的是在performTraversals方法里面。对应着三个重要的方法:
测量:ViewRootImpl.performMeasure
布局:ViewRootImpl.performLayout
绘制:ViewRootImpl.performDraw
最后放一个图: