我们知道 Activity 启动后就可以看到我们写的 Layout 布局界面,Activity 从 setContentView() 到显示中间做了什么呢?下面我们就来分析下这个过程。
如不了解 Activity 的启动过程请参阅:Activity 启动过程
本文主要对于以下问题进行分析:
在 Activity 创建过程中执行 scheduleLaunchActivity() 之后便调用到了 handleLaunchActivity() 方法。
ActivityThread.handleLaunchActivity():
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
handleConfigurationChanged(null, null);
//初始化 WindowManagerService,主要是获取到 WindowManagerService 代理对象
WindowManagerGlobal.initialize();
//详情见下面分析
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
//详见下面分析 [onResume() - Window 显示过程]
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
...
}
...
}
...
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
//获取 ClassLoader
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//创建目标 Activity 对象
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
//创建 Application 对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
//详情见下面分析
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);
...
//回调 Activity.onCreate()
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
return activity;
}
...
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) {
attachBaseContext(context);
mWindow = new PhoneWindow(this); //创建 PhoneWindow
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
mApplication = application; //所属的 Application
...
//设置并获取 WindowManagerImpl 对象
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
可看出 Activity 里新建一个 PhoneWindow 对象。在 Android 中,Window 是个抽象的概念, Android 中 Window 的具体实现类是 PhoneWindow,Activity 和 Dialog 中的 Window 对象都是 PhoneWindow。
同时得到一个 WindowManager 对象,WindowManager 是一个抽象类,这个 WindowManager 的具体实现是在 WindowManagerImpl 中,对比 Context 和 ContextImpl。
Window.setWindowManager():
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
...
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
...
}
每个 Activity 会有一个 WindowManager 对象,这个 mWindowManager 就是和 WindowManagerService 进行通信,也是 WindowManagerService 识别 View 具体属于那个 Activity 的关键,创建时传入 IBinder 类型的 mToken。
mWindow.setWindowManager(..., mToken, ..., ...)
这个 Activity 的 mToken,这个 mToken 是一个 IBinder,WindowManagerService 就是通过这个 IBinder 来管理 Activity 里的 View。
回调 Activity.onCreate() 后,会执行 setContentView() 方法将我们写的 Layout 布局页面设置给 Activity。
Activity.setContentView():
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
PhoneWindow.setContentView():
public void setContentView(int layoutResID) {
...
installDecor();
...
}
PhoneWindow.installDecor():
private void installDecor() {
//根据不同的 Theme,创建不同的 DecorView,DecorView 是一个 FrameLayout
}
这时只是创建了 PhoneWindow,和DecorView,但目前二者也没有任何关系,产生关系是在ActivityThread.performResumeActivity 中,再调用 r.activity.performResume(),调用 r.activity.makeVisible,将 DecorView 添加到当前的 Window 上。
Activity 与 PhoneWindow 与 DecorView 关系图:
ActivityThread.handleResumeActivity():
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
//执行到 onResume()
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
boolean willBeVisible = !a.mStartedActivity;
...
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;
wm.addView(decor, l);
}
}
...
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
...
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
//添加视图,详见下面分析
r.activity.makeVisible();
}
}
//resume 完成
if (reallyResume) {
ActivityManagerNative.getDefault().activityResumed(token);
}
} else {
...
}
}
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) {
ActivityClientRecord r = mActivities.get(token);
if (r != null && !r.activity.mFinished) {
...
//回调 onResume()
r.activity.performResume();
...
}
return r;
}
Activity.makeVisible():
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
//详见下面分析
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
WindowManager 的 addView 的具体实现在 WindowManagerImpl 中,而 WindowManagerImpl 的 addView 又会调用 WindowManagerGlobal.addView()。
WindowManagerGlobal.addView():
public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {
...
ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
root.setView(view, wparams, panelParentView);
...
}
这个过程创建一个 ViewRootImpl,并将之前创建的 DecoView 作为参数传入,以后 DecoView 的事件都由 ViewRootImpl 来管理了,比如,DecoView 上添加 View,删除 View。ViewRootImpl 实现了 ViewParent 这个接口,这个接口最常见的一个方法是 requestLayout()。
ViewRootImpl 是个 ViewParent,在 DecoView 添加的 View 时,就会将 View 中的 ViewParent 设为 DecoView 所在的 ViewRootImpl,View 的 ViewParent 相同时,理解为这些 View 在一个 View 链上。所以每当调用 View 的 requestLayout()时,其实是调用到 ViewRootImpl,ViewRootImpl 会控制整个事件的流程。可以看出一个 ViewRootImpl 对添加到 DecoView 的所有 View 进行事件管理。
ViewRootImpl:
public ViewRootImpl(Context context, Display display) {
mContext = context;
//获取 IWindowSession 的代理类
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mThread = Thread.currentThread(); //主线程
mWindow = new W(this);
mChoreographer = Choreographer.getInstance();
...
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
//通过 Binder 调用,进入 system 进程的 Session
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
...
}
}
WindowManagerGlobal:
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
//获取 InputManagerService 的代理类
InputMethodManager imm = InputMethodManager.getInstance();
//获取 WindowManagerService 的代理类
IWindowManager windowManager = getWindowManagerService();
//经过 Binder 调用,最终调用 WindowManagerService
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {...},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
...
}
}
return sWindowSession
}
}
通过 binder 调用进入 system_server 进程。
Session:
final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {
//详情见下面
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
}
WindowManagerService:
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {
...
WindowToken token = mTokenMap.get(attrs.token);
//创建 WindowState
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
...
//调整 WindowManager 的 LayoutParams 参数
mPolicy.adjustWindowParamsLw(win.mAttrs);
res = mPolicy.prepareAddWindowLw(win, attrs);
addWindowToListInOrderLocked(win, true);
// 设置 input
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
// 创建 Surface 与 SurfaceFlinger 通信,详见下面[SurfaceFlinger 图形系统]
win.attach();
mWindowMap.put(client.asBinder(), win);
if (win.canReceiveKeys()) {
//当该窗口能接收按键事件,则更新聚焦窗口
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
}
assignLayersLocked(displayContent.getWindowList());
...
}
创建 Surface 的过程详见:SurfaceFlinger 图形系统
Activity 中 Window 创建过程:
Window 是 Android 中窗口的宏观定义,主要是管理 View 的创建,以及与 ViewRootImpl 的交互,将 Activity 与 View 解耦。
一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。
这是我博客长期更新的项目,欢迎大家 Star。
https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode
欢迎你「扫一扫」下面的二维码,关注我的公众号,可以接受最新的文章推送,有丰厚的抽奖活动和福利等着你哦!?
如果你有什么疑问或者问题,可以 点击这里 提交 issue,也可以发邮件给我 [email protected]。
同时欢迎你 来一起交流学习,群里有很多大牛和学习资料,相信一定能帮助到你!