你有没有想过要对Android的View与事件背后的机制做一个探究呢?
哪怕你只是创建一个只有一个按钮的Activity,你也可以有以下这些疑问:
- Activity究竟是怎么创建的?
- Activity的生命周期究竟是怎么回调过来的?
- Activity的页面是怎么加载出来的?
- 按钮的点击事件究竟是从哪儿来的?
Android系统底层已经封装的很好,它就像是一个黑箱子,我们无需知道它的内部原理,也能完成一般的简单开发需求。
然而,你真的对这些东西不感到好奇吗?
我认为,我们学习的过程,最好的方式,应该就像我们看远处的风景,首先我们看到的,应该是它的全貌,知道它的大概组成,每一个部分都是什么,然而一个部件的细节,要走近了才能看的清楚。
而效率低下的一种方式,就像是走迷宫,身陷其中,只看到局部,不知道周围是什么,也不知道它到底有多大,不知道这条路能不能走通,完全就是在不断地试错,最后迷失了方向。虽然最终也可以走出来,但是在这个竞争如此激烈的社会,它不会给你那么多时间慢慢地去摸索,当你出来时,别人已经甩了你九条街。
上面提出的每一个问题,如果深入来讲,都可以写出一个系列的文章。这里做个简述,从Activity的创建(是创建不是启动),到它的页面加载显示出来这个过程。
先解决一下几个问题:
Context什么时候创建?
AMS在Activity请求创建后,执行了一系列的操作之后,最终会通过Binder调用到IApplicationService中,来到我们自己的进程中。
ActivityStackSupervisor.java
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
// ...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
//...
}
这里的app.thread定义:
IApplicationThread thread; // the actual proc... may be null only if
// 'persistent' is true (in which case we
// are in the process of launching the app)
它的实现是ActivityThread的内部类,它通过继承IApplicationThread.Stub实现了IApplicationThread接口:
ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {... }
那么再看看ActivityThread的scheduleLaunchActivity():
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List pendingResults, List pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.intent = intent;
r.activityInfo = info;
//...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
这里创建了ActivityClientRecord,然后发送了一个消息给ActivityThread的内部类H,它继承自Handler。
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
} break;
// ...
}
Object obj = msg.obj;
}
}
继续看handleLaunchActivity():
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// 这里进入创建Activity流程
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
Bundle oldState = r.state;
// 创建之后就执行resume流程,在这里会使Activity的window可见
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
}
// ...
}
ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 我们Activity的Context就是在这里创建了
ContextImpl appContext = createBaseContextForActivity(r);
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
// 使用的是Instrumentation来创建Activity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
} catch (Exception e) {
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
// 设置Activity内的Context
appContext.setOuterContext(activity);
// 在这里面创建Window
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);
//生命周期方法:onCreate()
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!r.activity.mFinished) {
//生命周期方法:onStart()
activity.performStart();
}
}
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
}
return activity;
}
见注释, 我们Activity的Context就是在这里创建了
Application什么时候创建?
LoadedApk.java,也就是上面被ActivityThread调用
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
// 创建Application的Context
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
// 设置Application内的Context
appContext.setOuterContext(app);
} catch (Exception e) {
}
}
见注释,Application的Context在这时被创建
Context什么时候与Activity、Application关联?
见上面代码注释
Window什么时候创建?
Activity.java,也就是上面被ActivityThread调用
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) {
attachBaseContext(context);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mToken = token;
mApplication = application;
mActivityInfo = info;
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
}
ViewRootImpl什么时候创建?
以上Activity的创建过程完成了之后,会调用到我们的Activity的onCreate()方法,我们在里面调用setContentView(),看看Activity的setContentView():
Activity.java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
这里mWindow获取到的就是之前attach()方法创建的PhoneWindow了:
PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 这里创建了DecorView,里面已经添加了一个根据feature添加进去的一个LinearLayout
// 它一般都包含一个id为content的FrameLayout
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 将我们指定的layout加载到上面那个id为content的FrameLayout中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
// ...
}
到这里,Activity的整个视图结构就已经准备好了,但是这时候它还只是一个View,并没有添加到Window上。
那么到这时,AcitivtyThread的performLaunchActivity就执行完了,接下来会执行handleResumeActivity(),直接再贴一次上面的代码:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// 这里进入创建Activity流程
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
Bundle oldState = r.state;
// 创建之后就执行resume流程,在这里会使Activity的window可见
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
}
// ...
}
OK,继续:
ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
// TODO Push resumeArgs into the activity for consideration
r = performResumeActivity(token, clearHide, reason);
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();
// 设置decorview可见
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 将DecorView添加到WindowManager中
wm.addView(decor, l);
} else { ... }
}
}
}
}
}
在performResumeActivity()方法里,它就调用了activity.performResume()方法
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (r != null && !r.activity.mFinished) {
try {
r.activity.performResume();
}
return r;
}
而performResume里面发生了什么呢?
Activity.java
final void performResume() {
performRestart();
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
}
可以看到先调用了performRestart()方法,然后才是调用了Instrumentation的callActivityOnResume()方法。这也就是Activity生命周期中的前几个:onCreate()、onStart()、onRestart()、onResume()的来源。
那么去看看activity的WindowManager,WindowManager的实现是WindowManagerImpl,进去看看:
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
// ...
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
}
WindowManagerImpl将window的操作都委托给了WindowManagerGlobal。而WindowManagerGlobal是个单例,里面包含了所有委托给它管理的View、ViewRootImpl、LayoutParams:
public final class WindowManagerGlobal {
private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
private final ArrayList mParams =
new ArrayList();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
ViewRootImpl root;
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
root.setView(view, wparams, panelParentView);
}
}
到这里,ViewRootImpl就创建好了。
Activity中的view是如何绘制上去的?
那么继续看:
ViewRootImpl.java
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
// ...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
这里有个checkThread()方法要注意下:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
这个异常是不是很熟悉?子线程不能更新UI,就是从这里来的。
不过我们可以看到,当Activity创建好运行到这里时,已经是在Activity的onResume()之后了,这也就是为什么我们在onCreate()方法里,可以直接开一个子线程在里面更新UI而不会报错的原因。因为onCreate()执行时,这段代码根本就没机会执行。
OK,继续看它后面的scheduleTraversals()方法:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 在这个mTraversalRunnable里开始遍历子视图决定是否需要刷新
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
// ...
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
performTraversals();
}
}
OK,进入到了著名的performTraversals()方法了,它的作用主要就是遍历View的子View,看是否需要更新,代码非常长(足足有793行!),挑重点:
private void performTraversals() {
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
if (!mStopped || mReportNextDraw) {
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
// 开始测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
// 开始layout
performLayout(lp, mWidth, mHeight);
}
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw && !newSurface) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 开始绘制
performDraw();
}
mIsInTraversal = false;
}
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
}
}
测量过程直接调用view的measure方法,view自己内部会遍历自己的children,直到测量完整个view树。
layout过程:
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) {
final View host = mView;
try {
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
int numViewsRequestingLayout = mLayoutRequesters.size();
if (numViewsRequestingLayout > 0) {
// requestLayout() was called during layout.
// If no layout-request flags are set on the requesting views, there is no problem.
// If some requests are still pending, then we need to clear those flags and do
// a full request/measure/layout pass to handle this situation.
ArrayList validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
false);
if (validLayoutRequesters != null) {
// Process fresh layout requests, then measure and layout
int numValidRequests = validLayoutRequesters.size();
for (int i = 0; i < numValidRequests; ++i) {
final View view = validLayoutRequesters.get(i);
view.requestLayout();
}
measureHierarchy(host, lp, mView.getContext().getResources(),
desiredWindowWidth, desiredWindowHeight);
mInLayout = true;
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}
} finally {
}
}
layout过程看起来有点长,但其实在try下面的那次layout就已经完成了。
后面的代码处理的是在本次layout过程中,又有新的view请求了requestLayout,那么这些view会被放入到一个列表中暂时保存,等第一波layout完成之后,再来检查这个列表,看哪些是刚才已经layout过了的,哪些已经是不可见了的,等等,过滤掉一些之后如果还有,那么先循环调用它们自身的requestLayout方法,然后ViewRootImpl再执行一次layout。
下面看看performDraw()方法:
private void performDraw() {
try {
draw(fullRedrawNeeded);
} finally {
mIsDrawing = false;
}
}
它又调用了draw()方法:
private void draw(boolean fullRedrawNeeded) {
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
}
最终它还是调用到了View.draw(canvas)方法:
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
mView.draw(canvas);
}
关于View具体的measure-layout-draw流程,可以参考我的这篇文章:Android View的绘制流程,这里不再赘述。
关于事件的来龙去脉,下篇文件见。
小结
以上,就完成了Activity从AMS调用的用户进程这边开始,一直到Activity的View完成绘制并显示。总结起来,它大致做了以下事情:
- 创建Activity及其Context
- 创建Application及其Context
- 给Activity创建Window,并赋予WindowManager
- 调用Activity的onCreate()方法,我们手动调用setContentView()
- 创建DecorView,将我们的contentView设置到DecorView中
- 调用Activity的onStart()方法
- 调用Activity的onResume()方法
- 将DecorView添加到Window中,其实是使用了WindowManagerImpl,又委托了WindowManagerGlobal来添加
- 创建了ViewRootImpl,它是Activity与Window之间沟通的桥梁
- ViewRootImpl先后调用setView、requestLayout()、performTraversals(),开始遍历绘制DecorView及其子view,完成Activity页面的显示