Android Activity创建到View的显示过程
前言
当我们点击桌面图标启动App,到App显示完成,这中间到底经历了什么呢?了解了这部分内容,将会对Activity、Window、View之间联系与区别加深印象,更好指导我们编写代码。
通过这篇文章,你将了解到:
1、Activity创建到onCreate()、onResume方法执行
2、Application创建到onCreate方法执行
3、Activity生命周期监听
4、Window/WindowManager创建与联系
5、WindowManager addView过程
6、ViewRootImpl创建与View三大过程
7、Android屏幕刷新信号简单了解
Android Main方法
写过JavaSE应用或者其它应用的都知道,一个程序的入口是main()方法,那么Android的main()方法在哪呢?
ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// Install selective syscall interception
AndroidOs.install();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
当进程被fork出来后,执行main()方法。该方法很短,简短列出关注的地方:
- 构造ActivityThread实例
- 开启Looper循环(主线程也就是UI线程的Looper)
Looper是Android消息(事件)驱动的核心,感兴趣的可移步:Android事件驱动Handler-Message-Looper解析
Application创建过程
来看看ActivityThread.attach()方法:
@UnsupportedAppUsage
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//mgr 为ActivityManagerService 实例
final IActivityManager mgr = ActivityManager.getService();
try {
//mAppThread 为ApplicationThread
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
//省略
}
}
ActivityManagerService.java 方法
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
//把IApplicationThread thread对象传递给AMS,AMS通过thread传递数据到当前进程
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
在attachApplicationLocked(thread, callingPid, callingUid, startSeq);关注两个点:
1、ActivityThread的bindApplication方法
2、mAtmInternal.attachApplication(app.getWindowProcessController()):
先说第一点:
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions) {
//省略
AppBindData data = new AppBindData();
//省略
//切换到主线程
sendMessage(H.BIND_APPLICATION, data);
}
接着在handleMessage()里接收到H.BIND_APPLICATION信息后调用handleBindApplication(data),该方法里主要关注以下几点:
private void handleBindApplication(AppBindData data) {
//省略
if (ii != null) {
//省略
} else {
//创建Instrumentation 对象,ActivityThread持有该对象引用
//Application、Activity 的创建都是需要调用instrumentation相关方法
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
//省略
Application app;
try {
//A
//info 是LoadedApk类型,顾名思义,存放的是apk包的一些信息,如应用名,数据存储目录等
app = data.info.makeApplication(data.restrictedBackupMode, null);
//省略
try {
//B
//app创建完毕,调用方法通知
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
//省略
}
} finally {
//省略
}
}
继续分析上述代码注释里的A、B两点。
先来看看A
LoadedApk.makeApplication()方法:
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//传过来的instrumentation=null
//app已经创建过,无需创建
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
//省略
try {
//获取ClassLoader
java.lang.ClassLoader cl = getClassLoader();
//省略
//创建app 的context,注意并不是app本身
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//通过Instrumentation 创建app
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
//省略
}
//赋值
mApplication = app;
//省略
return app;
}
创建Application对象交给了Instrumentation.newApplication方法:
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
//通过反射创建Application对象,会调用默认构造方法
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
//将ContextImpl对象赋值给Application的mBase引用
app.attach(context);
return app;
}
再来看看B
public void callApplicationOnCreate(Application app) {
//实际就是调用Application的onCreate方法通知App创建完毕
app.onCreate();
}
我们现在创建Application子类App
public class App extends Application {
public App() {
}
@Override
public void onCreate() {
super.onCreate();
}
}
通过上述分析,可以知道App()、onCreate()的调用时机了。至此Application创建过程分析完毕。
Activity创建过程
Application创建完毕,就该启动Activity了,就是我们熟知的“MainActivity”了。之前说的attachApplicationLocked()里的第二个点:mAtmInternal.attachApplication(app.getWindowProcessController());
mAtmInternal是ActivityTaskManagerService类型
@Override
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
synchronized (mGlobalLockWithoutBoost) {
return mRootActivityContainer.attachApplication(wpc);
}
}
ActivityStackSupervisor.java
boolean attachApplication(WindowProcessController app) throws RemoteException {
final String processName = app.mName;
//省略
final int size = mTmpActivityList.size();
for (int i = 0; i < size; i++) {
final ActivityRecord activity = mTmpActivityList.get(i);
if (activity.app == null && app.mUid == activity.info.applicationInfo.uid
&& processName.equals(activity.processName)) {
try {
//启动activity
if (mStackSupervisor.realStartActivityLocked(activity, app,
top == activity /* andResume */, true /* checkConfig */)) {
didSomething = true;
}
} catch (RemoteException e) {
}
}
}
//省略
return didSomething;
}
接着调用:mService.getLifecycleManager().scheduleTransaction(clientTransaction);
LaunchActivityItem传递到ActivityThread,回到了我们熟悉的地方。最终调用ActivityThread里的handleLaunchActivity()方法:
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
//省略
//初始化WindowManagerService,后面添加窗口会用到
WindowManagerGlobal.initialize();
final Activity a = performLaunchActivity(r, customIntent);
//省略
return a;
}
重点在performLaunchActivity里。
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
//省略
//创建ContextImpl类型的上下文
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
//和App创建过程一样,Instrumentation通过反射构造Activity实例
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
} catch (Exception e) {
}
try {
//创建app,因为之前已经创建过,因此这里直接返回Application对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//省略
if (activity != null) {
Window window = null;
appContext.setOuterContext(activity);
//重点方法 A
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
if (customIntent != null) {
activity.mIntent = customIntent;
}
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
//设置主题
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
//通知Activity创建成功,重点方法 B
mInstrumentation.callActivityOnCreate(activity, r.state);
}
//记录activity
r.activity = activity;
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
}
return activity;
}
重点方法 A
Activity对象创建完毕后,需要关联一些属性,实际上就是初始化其成员变量,比如Context、Window、WindowManager、Application等。
Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
//关联mBase
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//创建window,window是抽象类,这里是创建其子类PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//window一些回调接口,比如触摸/物理按键事件分发,焦点变化,依附/去依附 window等
mWindow.setCallback(this);
//ui线程即是当前线程
mUiThread = Thread.currentThread();
//ActivityThread
mMainThread = aThread;
//引用Instrumentation
mInstrumentation = instr;
//记录token
mToken = token;
//记录Application
mApplication = application;
//标题
mTitle = title;
//创建windowManager,并作为Window的成员变量
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
//Activity WindowManager变量赋值
mWindowManager = mWindow.getWindowManager();
//注:以上有些地方省略了
}
重点方法 B
和Application类似,Activity创建完成后,通知Activity回调其onCreate方法,这动作的发起还是由Instrumentation开始。
ActivityThread.java
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
Activity.java
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
//Activity里的onCreate方法,子类都会重写这方法
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
}
@CallSuper
protected void onCreate(@android.annotation.Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
//省略
//Activity分发创建事件
dispatchActivityCreated(savedInstanceState);
//省略
}
private void dispatchActivityCreated(@android.annotation.Nullable Bundle savedInstanceState) {
//Application里的回调集合
getApplication().dispatchActivityCreated(this, savedInstanceState);
//Activity里的回到集合
Object[] callbacks = collectActivityLifecycleCallbacks();
//这里的集合是ActivityLifecycleCallbacks类型,我们平时想监听Activity生命周期可以通过
//registerActivityLifecycleCallbacks()方法 Application和Activity里都有此方法
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
//通知观察者Activity onCreate()方法已经执行完毕
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityCreated(this,
savedInstanceState);
}
}
}
到此Application和Activity已经创建完毕。你可能比较疑惑,那View什么时候显示呢?
View的创建过程
新建Activity的时候,会绑定layout,就从这开始分析。
Activity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//绑定layout
setContentView(R.layout.activity_main);
}
public void setContentView(@LayoutRes int layoutResID) {
//Activity交给代理 AppCompatDelegateImpl.java 处理
//创建AppCompatDelegateImpl对象,并将Activity window变量赋予AppCompatDelegateImpl
//mWindow 成员变量
getDelegate().setContentView(layoutResID);
}
来看看AppCompatDelegateImpl.java
public void setContentView(int resId) {
/**
* 1、创建DecorView,并将AppCompatDelegateImpl mWindow赋值给DecorView mWindow变量
* 2、PhoneWindow mDecor 引用持有DecorView对象,也就是说DecorView与PhoneWindow相互持有
* 对方
*
*/
ensureSubDecor();
//取出DecorView里名为content的子view,并将其里面的子子view移除
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
//加载自定义的layout,实际上就是构建View树的过程,一般都是ViewGroup
//将自定义的layout作为子View add到contentParent里
//至此DecorView已经有我们自己自定义的内容了
LayoutInflater.from(mContext).inflate(resId, contentParent);
}
至此,整个View树就创建出来了,也就是说在Activity创建的时候就把View树也创建了。虽然简单关联了Window和DecorView(互相持有引用),但是貌似并没有看出什么特别的价值,View何时被添加到Window里呢?
WindowManager addView过程
之前说过,Activity生命周期由AMS管理,我们分析了Activity创建通知由AMS发送给ActivityThread,那么Activity的start、resume时,ActivityThread做了哪些处理呢?
来看看handleResumeActivity():
ActivityThread.java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
//最终调用到Activity onResume()
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r.window == null && !a.mFinished && willBeVisible) {
//取出Activity里的window,这是在Window创建时关联上的
r.window = r.activity.getWindow();
//取出window里的DecorView,这是在Activity.setContentView(),DecorView创建时关联上的
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//也是在Activity创建时关联上的 windowManager继承了ViewManager接口
//windowManager本身也是个接口
ViewManager wm = a.getWindowManager();
//window的布局属性,在Window创建时就生成,默认宽高填满父窗口
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
//window 窗口类型
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
//省略
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//重点方法 A windowManager添加DecorView
wm.addView(decor, l);
} else {
}
}
}
//省略
}
重点方法 A
wm.addView(decor, l),addView是ViewManager接口里的方法:
public interface ViewManager
{
//添加View
public void addView(View view, ViewGroup.LayoutParams params);
//更新View
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
//移除View
public void removeView(View view);
}
WindowManager是接口,那么它的实现类是哪个呢?答案就是在创建WindowManager的时候:
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
可以看出,WindowManagerImpl是WindowManager的实现类,来看看其addView()
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
//交由WindowManagerGlobal处理,WindowManagerGlobal是个类,提供单例访问
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
//省略
//ViewRootImpl
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
//创建ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
//这里传入的View是DecorView,设置DecorView的layoutParam,默认是填充父控件
view.setLayoutParams(wparams);
//WindowManagerGlobal是全局共享的
//可能会有多个DecorView(每个Activity都有,Dialog也有等)
//因此需要List来记录相关信息
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
//调用ViewRootImpl setView方法
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
}
}
}
WindowManagerGlobal addView最终调用了ViewRootImpl的setView方法:
该方法比较长,选择重点解释:
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
//记录DecorView
mView = view;
//省略
//开启View的三大流程(measure、layout、draw)
requestLayout();
try {
//添加到WindowManagerService里,这里是真正添加window到底层
//这里的返回值判断window是否成功添加,权限判断等。
//比如用Application的context开启dialog,这里会添加不成功
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
setFrame(mTmpFrame);
} catch (RemoteException e) {
}
if (mInputChannel != null) {
//注册事件监听,当native层触摸事件/物理键 事件到来时先分发到这
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
//设置 ViewParent mParent;
//该变量记录每个View的父view,在View的invalidate、requestLayout等
//场合用来一层层往上遍历view树
//这里记录着:DecorView的Parent是ViewRootImpl
view.assignParent(this);
//省略
//输入事件接收
}
}
}
通过mWindowSession.addToDisplay(),我们知道Window已经和WindowManagerService挂上关系了。剩下的就是View本身的measure、layout、draw过程了,实际上入口就是上边的requestLayout()。
View绘制的三大流程
一个View从构造到显示,需要经历以下步骤:
1、创建View对象(构造)
2、确定View占的空间尺寸(measure)
3、确定了空间尺寸,就需要确定摆放在哪个位置(layout)
4、确认了摆放位置,就需要确定在上面展示些什么东西(draw)
requestLayout
下面的内容涉及到Looper,有疑问的可先看此篇:Android事件驱动Handler-Message-Looper解析
ViewRootImpl.java
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查是否是主线程,如果不是则直接抛出异常,ViewRootImpl创建的时候生成一个主线程引用
//用当前线程和引用比较,如果是同一个则是主线程
//这也是为什么在子线程对View进行更新、绘制会报错的原因
checkThread();
//用来标记需要进行layout
mLayoutRequested = true;
//绘制请求
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
//标记一次绘制请求,用来屏蔽短时间内的重复请求
mTraversalScheduled = true;
//往主线程Looper队列里放同步屏障消息,用来控制异步消息的执行
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//放入mChoreographer队列里
//主要是将mTraversalRunnable放入队列
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
//省略
}
}
这里引入了Choreographer类,该类是ViewRootImpl构造时候创建的,通过ThreadLocal方式获取
Choreographer.java
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
//ViewRootImpl在主线程构造,这里获取的是主线程的looper
Looper looper = Looper.myLooper();
//构造Choreographer对象
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
return choreographer;
}
};
private Choreographer(Looper looper, int vsyncSource) {
//记录looper
mLooper = looper;
//定义Handler接收message
mHandler = new FrameHandler(looper);
//定义DisplayEventReceiver子类,用来接送底层刷新信号
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;;
//内部队列,用来维护各种请求,比如Traversal callback
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
放入队列:
Choreographer.java
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//放入队列
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//立即执行
scheduleFrameLocked(now);
} else {
//异步执行
}
}
}
最后调用到DisplayEventReceiver scheduleVsync方法:
DisplayEventReceiver.java
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+ "receiver has already been disposed.");
} else {
//native 方法,注册同步脉冲信号事件,告诉底层我需要刷新信号了,记得你的刷新时间到了,给我发送信号
//底层每16ms刷新一次,如果上层没有注册同步脉冲信号事件,则底层刷新的时候不会通知上层。
nativeScheduleVsync(mReceiverPtr);
}
}
好了,到这里requestLayout()已经完成了,就等待底层的刷新信号了。
秉着在哪里注册,就在哪里接收的原则,来看看DisplayEventReceiver类,找到了dispatchVsync方法:
DisplayEventReceiver.java
// Called from native code.
@SuppressWarnings("unused")
@UnsupportedAppUsage
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
//由DisplayEventReceiver子类FrameDisplayEventReceiver重写
onVsync(timestampNanos, physicalDisplayId, frame);
}
DisplayEventReceiver.java
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
//省略
//构造Message,并使用this,也就是回调自身run方法
Message msg = Message.obtain(mHandler, this);
//设置为异步消息,遇到屏障消息优先执行异步消息
//确保刷新信号能能够及时执行,也就是view绘制优先级是最高的
msg.setAsynchronous(true);
//发送消息
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
//执行刷新消息
//最终是取出mCallbackQueues里的方法执行
doFrame(mTimestampNanos, mFrame);
}
doFrame里取出的方法在什么时候放入的呢?就是之前
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
放入的。因此doFrame最后会回调mTraversalRunnable run方法
ViewRootImpl.java
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
//没有取消绘制的话则开始绘制
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
//真正开始执行measure、layout、draw等方法
performTraversals();
}
}
兜兜转转又回到了ViewRootImpl里。
requestLayout总结为:
1、将绘制请求添加到待执行队列,并发送消息给底层,表示自己有内容需要刷新。这时候reqeustLayout已经执行完毕了。
2、底层间隔时间刷新时,检测到上层的注册信号,因此发送给上层表示我这边已经刷新了,你赶紧换换你的界面吧。
3、收到底层信号时,发送到主线程looper队列里,并标记我这是要告诉别人这是界面刷新的信号哦,耽搁不得,赶紧优先执行。
4、执行第一步的请求,进行view三大绘制流程。
这里有两个问题需要注意一下,还记得代码里提及的一些标记,过滤短时间内的重复请求。
1、mTraversalScheduled 标记,如果这次绘制请求没有被回调执行之前,那么下次请求将忽略,比如短时间内重复的requestLayout。
2、mFrameScheduled 标记,如果底层的刷新信号没有来之前,再次发送给底层的信号将被忽略。
总结
至此,从Application到Activity创建再到View被添加到Window,直至发起绘制整个过程已经梳理完毕。简单归纳一下几者之间关系:
1、Activity通过Window来展示内容
2、Window通过ViewRootImpl管理View Tree
3、真正内容是通过View来展示的
最后用一张图来言简意赅表明整个过程:
image.png
requestLayout时用图表示:
image.png
本文基于Android 10.0源码。
接下来将会分析:
1、Android各种Context的前世今生
2、DecorView一窥全貌及其运用--Activity侧滑关闭
3、Window/WindowManager解析
4、View measure/layout/draw 完全解析
5、Android触摸事件(TouchEvent)分发
6、Android KeyEvent分发
7、RecyclerView原理解析之分割线
8、其它
有兴趣的可以关注后续文章。