问题
在Activity的周期方法onCreate()调用getHeight()为什么返回值为0?那在onResume()方法中可以获取到吗?那调用getMeasureHeight()可以获取到值吗?我们从源码分析一下。
Activity启动简述
其实,这里就涉及到Activity启动流程的问题,要点就是Activity.onCreate()/onStart()/onResume()等生命周期方法和view的绘制哪一个先执行。那么我们就从activity启动流程作为切入口来探究。ActivityThread.main()方法中通过binder通信与AMS取得联系,绑定application。AMS接收到请求后,会调用attachApplicationLocked()方法,其中第一步调用ApplicationThread.bindApplication()进行application绑定,第二步调用ApplicationThread.attachApplicationLocked()启动activity。ApplicationThread收到后最终会调用到ActivityThread.handleLaunchActivity()中,此时,应用进程就要真正开始启动activity。随后又会调用ActivityThread.handleResumeActivity()开始展示activity,以上是activity启动的简述,没看过activity启动的同学可能会不理解,建议学习一下。
handleResumeActivity方法
handleResumeActivity这个方法是我们重点关注的方法,在这个方法中,会将DecorView添加到window中。而添加之后,就会进行View的绘制。在调用handleResumeActivity之前,handleLaunchActivity中已经通过仪表盘创建了activity并调用了onCreate()方法,所以,在onCreate()中getMeasureHeight()/getHeight()获取为0。那么在onResume()方法中会获取到值吗?答案就在handleResumeActivity()方法中,如下:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
//调用performReusmeActivity,其中会调用activity.onResume()
ActivityClientRecord r = performResumeActivity(token, clearHide);
......
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();
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;
//将decorView添加到window中,这也是View绘制开始的起点
wm.addView(decor, l);
}
}
}
可以清楚的看到,performResumeActivity()调用在wm.addView()之前,所以在onResume()中是获取不到高度的。
performResumeActivity()如下:
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide) {
ActivityClientRecord r = mActivities.get(token);
if (r != null && !r.activity.mFinished) {
if (clearHide) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
try {
r.activity.onStateNotSaved();
....
r.activity.performResume();
....
} catch (Exception e) {
....
}
}
return r;
}
调用activity.performResume(),其中会通过仪表盘调用onResume():
后边的代码就不贴了,有兴趣的同学可以查看源码。