#本文基于Android 8.0源码,流程梳理,权当总结和笔记
结论先行:
1、context.startActivity
2、ActivityThread#main()---attach()和AMS建立连接
3、Activity收到onCreate回调,setContentView(layoutId),new DecorView
4、ActivityThread收到handleLaunchActivity回调---addView,add的就是上面的new DecorView
5、ViewRootImpl开启了measure、layout、draw等操作
附上流程图:
#1.Android也是Java程序,那么必然有个main方法作为入口,即ActivityThread.java#main
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
//attach
thread.attach(false);
Looper.loop();
//主线程的loop是一直在跑着的,一旦停止那么会抛出异常,同时也解释了我们创建的Hanlder,如果没有指定loop的线程的话,就是默认在主线程
throw new RuntimeException("Main thread loop unexpectedly exited");
}
attach方法的主要作用是为了和AMS建立连接,以便于获取Activity生命周期回掉的消息。
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
#context.startActivity,这句是启动Activity的方法。
关于Activity的启动,这里不详细说,只需要知道最后经过各种调用来到了ActivityThread.java#scheduleLaunchActivity(),然后调用了handleLaunchActivity()方法,接着又调用到了scheduleResumeActivity(),同样真正做事的是handleResumeActivity()
#下面看下handleResumeActivity这个方法具体做了哪些事情?
思考:其实在这里就可以很清楚的解释为什么在Actviity的onCreate方法里获取不到view的宽高或者获取到为0了,因为这个时候view都还没有被add到PhoneWindow中,就更别提measure了。
ActivityClientRecord r = mActivities.get(token);
#1、r = performResumeActivity(token, clearHide, reason);
r.window = r.activity.getWindow();
#2、View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
ViewRootImpl impl = decor.getViewRootImpl();
if (!a.mWindowAdded) {
a.mWindowAdded = true;
#3、wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
这里很重要,一步步分析:
1、通过token从ActivityClientRecord中获取对应的Activity,token可以理解为一个身份的标志。
2、View decor = r.window.getDecorView();
这里getDecorView是Window.java的一个抽象方法
/*
*
* @return Returns the top-level window decor view.
*/
public abstract View getDecorView();
它的实现在PhoneWindow.java
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
那么这里的mDecor是什么?它是DecorView,什么是DecorView,一张图说明:
那么它是在哪里赋值的呢?
回到AMS,在告诉ActivityThread.java#handleResumeActivity消息之前调用了Activity生命周期的onCreate方法,开发者可以在这个方法里设置自己定义的布局文件:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//通过setContentView方法设置自己定义的布局文件
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
}
看这个方法setContentView,在这个方法里初始化mDecor,并把我们自己定义的布局文件activity_main.xml添加到mDecor中。
详细可参考:Android FrameWork之旅 --- setContentView
所以decor就是一个add了我们自定义的布局文件的ViewGroup。
Ok,到这里我们定义的布局文件终于被add到DecorView中了,那么什么时候真正的显示在屏幕之上呢?
继续ActivityThread.java#handleResumeActivity的第三个步骤:
final Activity a = r.activity;
ViewManager wm = a.getWindowManager();
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
wm是什么?是一个ViewManager对象,所以wm.addView又是把decor怎么了?
那就要看看addView方法做了什么了?
该方法是在ViewManager里声明的,ViewManager是一个interface:
public void addView(View view, ViewGroup.LayoutParams params);
这里最终调用到了WindowManagerImpl.java#addView方法,该方法又调用了
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
所以,最后的实现是在WindowManagerGlobal.java中:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
ViewRootImpl root;
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//mViews是一个ArrayList对象,具体做什么的还没研究过
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//重点看这里
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e
走到了ViewRootImpl.java#setView方法,到这里开始对这个view做各种操作:
// 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();
GoOn:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查当前操作是否在UI线程,也就是Android的主线程
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
scheduleTraversals()方法中最主要是调用到了doTraversal:
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
//看我看我看我
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
后续依次通过performMeasure()、performLayout()及performDraw()来调用View的三个非常重要的方法:
measure()、layout()及draw()。