今天我们一起来看五道 Activity 生命周期的面试题,相信看完之后面试官再问到相关的问题,你就能胸有成竹了。
A Activity 打开 B Activity 时都有哪些生命周期回调。
这道题相信很多同学都有遇到过,简单:
A.onPause -> B.onCrete -> B.onStart -> B.onResume -> A.onStop
Naive ! 这样回答只是及格,因为仅在 B Activity 的 launchMode 为 standard 或者 B Activity 没有可复用的实例时是这样的。
当 B Activity 的 launchMode 为 singleTop 且 B Activity 已经在栈顶时(一些特殊情况如通知栏点击、连点),此时只有 B 页面自己有生命周期变化:
B.onPause -> B.onNewIntent -> B.onResume
当 B Activity 的 launchMode 为 singleInstance ,singleTask 且对应的 B Activity 有可复用的实例时,生命周期回调是这样的:
A.onPause -> B.onNewIntent -> B.onRestart -> B.onStart -> B.onResume -> A.onStop -> ( 如果 A 被移出栈的话还有一个 A.on Destory)
把几种情况都回答出来就能加分啦,同时也要做好聊 launchMode 的准备。
弹出 Dialog 对生命周期有什么影响
我们知道,生命周期回调都是 AMS 通过 Binder 通知应用进程调用的;而弹出 Dialog、Toast、PopupWindow 本质上都直接是通过 WindowManager.addView() 显示的(没有经过 AMS),所以不会对生命周期有任何影响。
如果是启动一个 Theme 为 Dialog 的 Activity , 则生命周期为: A.onPause -> B.onCrete -> B.onStart -> B.onResume 注意这边没有前一个 Activity 不会回调 onStop,因为只有在 Activity 切到后台不可见才会回调 onStop;而弹出 Dialog 主题的 Activity 时前一个页面还是可见的,只是失去了焦点而已所以仅有 onPause 回调。
Activity 在 onResume 之后才显示的原因是什么
虽然我们设置 Activity 的布局一般都是在 onCreate 方法里调用 setContentView 。里面是直接调用 window 的 setContentView,创建一个 DecorView 用来包住我们创建的布局。详情如下:
PhoneWindow.java public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } … // 加载布局,添加到 mContentParent // mContentParent 又是 DecorView 的一个子布局 mLayoutInflater.inflate(layoutResID, mContentParent); }
然而这一步只是加载好了布局,生成一个 ViewTree , 具体怎么把 ViewTree 显示出来,答案就在下面:
ActivityThread.java public void handleResumeActivity(…){ // onResume 回调 ActivityClientRecord r = performResumeActivity(…) final Activity a = r.activity; if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); ViewManager wm = a.getWindowManager(); wm.addView(decor, l);// 重点 } }
WindowManager 的 addView 方法最终将 DecorView 添加到 WMS ,实现绘制到屏幕、接收触屏事件。具体的调用链如下:
WindowManagerImpl.addView -> WindowManagerGlobal.addView -> ViewRootImpl.setView -> ViewRootImpl.requestLayout() // 执行 View 的绘制流程 // 通过 Binder 调用 WMS ,WMS 会添加一个 Window 相关的对象 // 应用端通过 mWindowSession 调用 WMS // WMS 通过 mWindow (一个 Binder 对象) 调用应用端 mWindowSession.addToDisplay(mWindow) mWindow (一个 Binder 对象) 调用应用端 mWindowSession.addToDisplay(mWindow)
|