启动一个Activity
startActivity
最终会走到ActivityThread的performLaunchActivity
这个函数里面会经过层层深入会调用 Activity 的 OnCreate() 方法,而在 performLaunchActivity() 中调 OnCreate() 方法前会调用 Activity 的 attach() 方法
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, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//创建PhoneWindow,并设置回调
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(mWindowControllerCallback);
mWindow.setCallback(this);
//将window跟windowmanager绑定
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
//设置管理window的windowmanager
mWindowManager = mWindow.getWindowManager();
继续看Window源码setWindowManager
/**
* Set the window manager for use by this Window to, for example,
* display panels. This is <em>not</em> used for displaying the
* Window itself -- that must be done by the client.
*
* @param wm The window manager for adding new windows.
*/
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
这里没有理解清楚是如何获取wms
该方法里面可以看到如果传入的 wm 为空则将其重新赋值。这里其实是获取了 WindowManagerService 的代理,因为 WindowManagerService 和 Activity 所在的应用不在一个进程里,这里是通过 Binder 通信获取的一个 WindowManagerService 代理。获取完 WindowManagerService 代理后通过它来创建出一个真正要用的 WindowManager 并赋值。即这句代码:
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
这里主要就是获取一个WindowManagerImpl
attatch主要创建出activity的window绑定windowmanager,从而获取管理当前window的windowmanager,但是并没有将activity的view添加到window
- 继续看setContentView
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
查看PhoneWindow源码setContentView
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
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 {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
主要关注installDecor()
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
}
通过源码得知,如果当前DecorView为空,那么就创建一个,并且跟window进行绑定,DecorView 是 Activity 中的顶级 View,是一个 FrameLayout。
不过现在仍然没有将对应的画面展示到手机屏幕上
Window 加入到 WindowManager 这一过程要在调用完 Acitivy 的 onResume() 方法后来实现,之后会调用 Activity 的 makeVisible():
/**
* Control whether this activity's main window is visible. This is intended
* only for the special case of an activity that is not going to show a
* UI itself, but can't just finish prior to onResume() because it needs
* to wait for a service binding or such. Setting this to false allows
* you to prevent your UI from being shown during that time.
*
* <p>The default value for this is taken from the
* {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
*/
public void setVisible(boolean visible) {
if (mVisibleFromClient != visible) {
mVisibleFromClient = visible;
if (mVisibleFromServer) {
if (visible) makeVisible();
else mDecor.setVisibility(View.INVISIBLE);
}
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
这个函数里首先判断 Window 是否已经添加到 WindowManager 中,没有的话取出在刚刚 attach() 方法中创建的 WindowManager,将 DecorView 加入进去,这里的 DecorView 其实就是 Window 所持有那个。然后再将 DecorView 设置为显示状态,来显示我们的布局。
- 至此,我们需要关心WindowManager是如何进行管理Window
在实际使用中无法直接访问 Window,对 Window 的访问必须通过 WindowManager。我们已经知道 WindowManager 提供的三个接口方法 addView、updateViewLayout 以及 removeView 都是针对 View 的,而这些 View 都被其对应的 Window 所持有,所以上面这些操作实际上相当于对 Window 的操作,WindowManager 是一个接口,它的真正实现由上文可知是 WindowManagerImpl 类。
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
可以知道,实际是交给了mGlobal进行处理,也就是WindowManagerGlobal
- 继续看WindowManagerGlobal源码的几个核心参数
//存储的是所有 Window 所对应的 View
private final ArrayList<View> mViews = new ArrayList<View>();
//mRoots 存储的是所有 Window 所对应的 ViewRootImpl
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
//mParams 存储的是所有 Window 所对应的布局参数
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
//mDyingViews 存储了那些正在被删除的 View 对象,或者说是那些已经调用了 removeView 方法但是操作删除还未完成的 Window 对象
private final ArraySet<View> mDyingViews = new ArraySet<View>();
在 addView () 方法中将这些相关对象添加到对应集合中。最后调用 root.setView() 方法,setView() 中会调用一个很重要的方法 requestLayout(),其主要是用来刷新页面,其中还有一个很重要的方法 addToDisplay
framework/base/services/core/java/com/android/server/wm/Session.java
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
mWindowSession 的类型是 IWindowSession,它是一个 Binder 对象,真正的实现类是 Session,这也就是之前提到的 IPC 调用的位置。也就是说在这里,完成了 WindowManager 和 WindowManagerService 的通信,将 Window 信息传给了WindowManagerService。
至此,得出结论setView() 方法里面会通过 mWindowSession 这个 Binder 对象将 Window 传给 WindowManagerService。WindowManagerService 来管理各个 Window 的大小和显示位置,来让 SurfaceFlinger 渲染。