Android
的窗口管理如图所示!
这里我也不说Window
了,我直接就说PhoneWindow
了,因为不管是Activity
还是Dialog
他们的Window
都是PhoneWindow
.
每个PhoneWindow
都对应一个WindowManagerImpl
,通过Window.setWindowManager()
方法进行WindowManagerImpl
的创建. 拿Acvitity
的创建来说,在ActivityThread
的performLaunchActivity
时候,调用了Activity.attach
方法,来看下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class 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, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken, IBinder shareableActivityToken) {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
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();
} }
|
在 第一行 创建了 PhoneWindow
对象,然后在 第二行 给当前 PhoneWindow
设置了 WindowManagerImpl
对象, 看下创建过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Activity{ void attach(){ mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); } } class PhoneWindow{ 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); } }
class WindowManagerImpl{ public WindowManagerImpl createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken); } }
|
在调用setWindowManager
的时候一定要传入一个WindowManager
对象,在我看来,比如Activity
的启动,这个…..然后比如Dialog,这个WindowManager
就是当前触发Dialog
显示的那个Activity
的WindowManagerImpl.
这里需要着重看下 标记1 的地方, parentwindow
是什么,他为什么如此重要,就像他的名字一样 父窗口, 每个WindowManagerImpl
里面都保留了当前的PhoneWindow
对象,目的是在addView
的时候,就可以知道新添加的Window
需要指定到哪个 windowToken 上.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class WindowManagerGlobal{ public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; parentWindow.adjustLayoutParamsForSubWindow(wparams); root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); root.setView(view, wparams, panelParentView, userId); } } }
|
现在我们来看下一个Window
是怎么被添加进去和管理的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| class ViewRootImpl{ void setView(){ int res = mWindowSession.addToDisplayAsUser(mWindow,mWindowAttributes,getHostVisibility(),mDisplay.getDisplayId(),userId,..) } }
class Session{ public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, requestedVisibility, outInputChannel, outInsetsState, outActiveControls); } }
class WindowManagerService{ public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); win.mToken.addWindow(win); } private DisplayContent getDisplayContentOrCreate(int displayId, IBinder token) { if (token != null) { final WindowToken wToken = mRoot.getWindowToken(token); if (wToken != null) { return wToken.getDisplayContent(); } }
return mRoot.getDisplayContentOrCreate(displayId); } }
class RootWindowContainer{ WindowToken getWindowToken(IBinder binder) { for (int i = mChildren.size() - 1; i >= 0; --i) { final DisplayContent dc = mChildren.get(i); final WindowToken wtoken = dc.getWindowToken(binder); if (wtoken != null) { return wtoken; } } return null; } }
|
现在看下标记1 标记2这时候的内存分布情况:
图1
图2
图3
看了这三张图你就能深刻理解到最上面图的意思了. 首先 RootWindowContainer
管理着所有的DisplayContent
,一个DisplayContent
代表一个屏幕.然后一个屏幕管理着所有的WindowToken
,一个WindowToken
管理这一组窗口,比如,两个Activity
,他们的WindowToken
一定是不一样的,如果是在Activity
里面启动了一个Dialog
,那么这两个窗口的WindowToken
就是一样的.