前言
對(duì)Window、WM、WMS、WMG等一系列有一定深度的理解,個(gè)人認(rèn)為對(duì)開發(fā)工作會(huì)有一定的幫助,是很重要的一部分,可以說(shuō)創(chuàng)建一個(gè)Activity就離不開Window,所以還是要掌握~
一:WindowManage 關(guān)聯(lián)類的名稱以及作用
- Window:窗口 ,抽象類
- PhoneWindo:繼承于Window,Window的實(shí)現(xiàn)類
- ViewManage: 接口類,只有三個(gè)方法(addView、updateViewLayout、removeView),WindowManage 繼承與它,入?yún)⒍际荲iew或者ViewGroup,說(shuō)明Window是以View的形式存在的
- WindowManage:接口類,顧名思義,window的管理類
- WindowManageImpl:WindowManage的實(shí)現(xiàn)類
- WindowManageGlobal: 全局單例,管理Window
二:WM系列類圖

三:從Activity的attach()說(shuō)起
在Activity的啟動(dòng)流程中,調(diào)用到ActivityThread.class的performLaunchActivity()方法,這個(gè)方法我們很熟悉了,activity先attach()在onCreate()
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...省略
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...省略
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, window, r.configCallback);
//先attach了Activity
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
//Instrumentation再去調(diào)用的onCreate方法
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
...省略
Activity的attach方法中又調(diào)用了setWindowManager()方法
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) {
...省略
//這里創(chuàng)建了PhoneWindow對(duì)象
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...省略
//這里調(diào)用了setWindowManager()方法
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...省略
}
Window的setWindowManager方法中創(chuàng)建了WindowManagerImpl實(shí)例,因?yàn)閃indowManagerImpl是WindowManage的實(shí)現(xiàn)類,創(chuàng)建的時(shí)候又把Window傳了進(jìn)去,看前面的WindowManage繼承ViewManage,是不是在Window這個(gè)類中,管理交給了mWindowManager成員了
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//注意:這里把Windiw實(shí)例傳了進(jìn)來(lái),所以為什么叫WindowManager
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
所以之后Window的addView等操作,都是交給了WindowManage去實(shí)現(xiàn),也就是WindowManageImpl去實(shí)現(xiàn)
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
可以看到WindowManageImpl又交給了mGlobal去實(shí)現(xiàn),mGlobal就是WindowManagerGlobal,全局單例
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Context mContext;
private final Window mParentWindow;
再看之前的類圖,是不是清楚了很多了
四:Window有哪些屬性
Window屬性無(wú)非就三個(gè):
- Window的類型
- Window的Flag
- Window的SoftInputMode
關(guān)于以上三點(diǎn),該文章已經(jīng)說(shuō)的非常詳細(xì)了:Android解析WindowManager(二)Window的屬性
五:WindowManagerGlobal.class類解析
5.1 我們先看下WindowManagerGlobal中重要的成員有哪些:
//單例的對(duì)象鎖
private final Object mLock = new Object();
...省略
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
可以看到有三個(gè)List,分別存放了View、ViewRootImpl、WindowManager.LayoutParams,這個(gè)后面會(huì)說(shuō)到
5.2 WindowManagerGlobal的addView過(guò)程
在第三步中說(shuō)到,WindowManageImpl最后交給了WindowManagerGlobal去addView
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...省略
//創(chuàng)建了布局參數(shù)對(duì)象
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
//如果當(dāng)前窗口要作為子窗口,就會(huì)根據(jù)父窗口進(jìn)行相應(yīng)調(diào)整
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
if (mSystemPropertyUpdater == null) {
...省略
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//view,root,wparams放入對(duì)應(yīng)的列表中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
//最后把相關(guān)參數(shù)都放入ViewRootImpl中
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
可以看到最后把view,root,wparams放入對(duì)應(yīng)的List中,再把參數(shù)ViewRootImpl中
5.3 ViewRootImpl 是干什么的:
- View樹的根并管理著View樹
- 觸發(fā)View的measure、layout、draw
- 輸入事件的中轉(zhuǎn)站
- 管理Surface
- 負(fù)責(zé)與WMS進(jìn)行進(jìn)程間通訊
ViewRootImpl 的setView方法做了些什么
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...省略
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
...省略
}
可看到mWindowSession是IWindowSession對(duì)象,它實(shí)在ViewRootImpl創(chuàng)建的時(shí)候WMG創(chuàng)建的
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrac
...省略
可以看到這里通過(guò)進(jìn)程間通訊的技術(shù)獲取到了WMS的Session對(duì)象
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
然后我們看Session做了什么
@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) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
調(diào)用了AMS的addWindow方法完成了添加Window
5.4 ViewRootImpl 線程檢測(cè):
關(guān)于ViewRootImpl 這個(gè)類還有一個(gè)要說(shuō)的,很多操作UI的方法都會(huì)調(diào)用到checkThread(),如果此時(shí)創(chuàng)建ViewRootImpl 的線程和更新操作UI的線程不是同一個(gè)的話,就會(huì)拋出異常
如果不同的線程會(huì)拋出異常,后續(xù)Handler相關(guān)的文章會(huì)說(shuō)到這點(diǎn)
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
public ViewRootImpl(Context context, Display display) {
mContext = context;
//可知是當(dāng)前ViewRootImpl創(chuàng)建時(shí)候的顯示
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
}
六:Window的更新過(guò)程
和添加Window類似
調(diào)用ViewManage的updateViewLayout方法-> WindowManage->WindowManageImpl->WindowManageGrobal的updateViewLayout方法
看下這個(gè)方法做了什么:
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (mLock) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
mParams.remove(index);
mParams.add(index, wparams);
root.setLayoutParams(wparams, false);
}
}
可知還是最后調(diào)用了ViewRootImpl 的相關(guān)方法,看下setLayoutParams()
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
...省略
scheduleTraversals();
}
}
看下scheduleTraversals()方法
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
scheduleTraversals方法中的Choregrapher是一個(gè)用于接收顯示系統(tǒng)的VSync信號(hào),在下一幀渲染的時(shí)候執(zhí)行一系列操作
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
看下doTraversal()又調(diào)用了performTraversals()
void doTraversal() {
...省略
performTraversals();
...省略
}
看下performTraversals()方法
private void performTraversals() {
...省略
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...省略
performLayout(lp, mWidth, mHeight);
...省略
performDraw();
...省略
}
可以看到這個(gè)方法完成了View的繪制流程
END
人的自由并不在于你想做什么就做什么,恰恰相反,自由是在于你可以不用去做你不想做的事情,我所追尋的是后一種自由