概述
前置知识
Window
是什么?Window
是一个组件,View
是由Window
呈现出来的。Window
实际上就是管理着View
,对Window
的操作最终都会转化成对View
的操作。- 经常使用的
Window
:Activity
、Dialog
、PopupWindow
、Toast
等。系统中常见的Window
:StatusBar
、NavigationBar
、InputMethod
(软键盘)等。StatusBar
、NavigationBar
等是在单独的进程中使用的。
问题
1.WindowManager.LayoutParam
(继承ViewGroup.LayoutParams
)类很重要,flags
,type
等等。
type
,相当于Window 的类型,主要分为3大类。
- 1-99对应应用Window(token 必须设置为Activity 的token,即Context需要设置为Activity)。Activity 中的Window 对应的type 是
TYPE_BASE_APPLICATION
,Dialog
默认的是TYPE_APPLICATION
,WindowManager.LayoutParams
默认构造函对应的type也是TYPE_APPLICATION
。 - 1000-1999对应子Window。PopupWindow 默认是
TYPE_APPLICATION_PANEL
。 - 2000-2999 对应的是系统Window。
Toast
对应TYPE_TOAST
,StatusBar
对应TYPE_STATUS_BAR
,NavigationBar
对应TYPE_NAVIGATION_BAR
,键盘对应着”TYPE_INPUT_METHOD”。
flags
,各种不一样属性,控制Window 的一些特殊显示。
2.Dialog
和PopupWindow
的异同。
Dialog
和PopupWindoow
都会在一个新的Window
中展示。Dialog
不能使用ApplicationContext
,上面就可以知道Dailog
是应用Window
,只能使用Activity
。PopupWindow
不能在Activity.onCreate
中创建。PopupWindow
默认是一个子Window
,需要在Activity
创建以后使用。PopupWindow
一定需要设置width
和height
,默认是0。Dialog
是创建了一个PhoneWindow
然后获取的DecorView
,所有默认有Title,而PopupWindow
没有。PopupWindow
默认不会响应Back键,可以设置popupWindow.setFocusable(true);
。- 通过
Activity
来管理Dialog
的时候,Activity.mManagedDialogs
,当Activity
后台销毁的时候再次进入可以恢复(参考Dialog.onSaveInstanceState
、Dialog.onRestoreInstanceState
)。而PopupWindow
没有恢复机制。
至于网上很多说PopupWindow
是阻塞式的而Dialog
是非阻塞式的,是非常误解人的。关于坑爹的PopupWindow的“阻塞”争议问题:Android没有真正的“阻塞式”对话框
3.Toast
展示以后可以将Toast点击的事件传递到下面的View,Dialog
以及Popupindow
都不行,跟WindowManager.LayoutParams.flags
有关。
4.Activity
设置windowSoftInputMode
属性的时候,会对Activity
的Window
有一些影响。
5.一个App 中有多少个Window
?应该是某个状态下Window
的个数,Activity
+Dialog
+PopupWindow
+Toast
+WindowManage.addView
。
基本操作
WindowManager
继承ViewManager
,基本的操作如下。操作的实际上是View
。WindowManagerImpl
保存着一族对应的mViews
、mRoots
、mParams
。对于每一个展示的Window
实际上对应着mViews[k]
、mRoots[k]
、mParams[k]
。具体可以看后面的流程分析。
// ViewManager.java
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
流程分析
Window.setStatusBarColor
流程(api 21以上)。
StatusBar
、NavigationBar
都是一个View展示在最上面和最下面??
1.Window.setStatusBarColor`。
// PhoneWindow.java
@Override
public void setStatusBarColor(int color) {
mStatusBarColor = color;
mForcedStatusBarColor = true;
if (mDecor != null) {
// 直接调用到了DecorView.updateColorViews()
mDecor.updateColorViews(null, false /* animate */);
}
}
2.DecorView.updateColorViews
。从代码中看就是修改了mNavigationColorViewState
和mStatusColorViewState
里面包含的View
的backgroundColor
。
// DecorView.java
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
// insets null
animate false
WindowManager.LayoutParams attrs = getAttributes();
// 获取系统状态栏的显示属性
int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
if (!mIsFloating && ActivityManager.isHighEndGfx()) {
boolean disallowAnimate = !isLaidOut();
disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
& FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
mLastWindowFlags = attrs.flags;
if (insets != null) {
// 省略相关代码
}
// 这里相当于是横竖屏判断
boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0;
int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset;
// 更新Navigation
updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
navBarSize, navBarToRightEdge, 0 /* rightInset */,
animate && !disallowAnimate);
boolean statusBarNeedsRightInset = navBarToRightEdge
&& mNavigationColorViewState.present;
int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
// 更新Status
updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
mLastTopInset, false /* matchVertical */, statusBarRightInset,
animate && !disallowAnimate);
}
// 省略代码
return insets;
}
3.DecorView.updateColorViewInt
// DecorView.java
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) {
// animate false
state.present = (sysUiVis & state.systemUiHideFlag) == 0
&& (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
&& ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|| force);
boolean show = state.present
&& (color & Color.BLACK) != 0
&& ((mWindow.getAttributes().flags & state.translucentFlag) == 0
|| force);
boolean showView = show && !isResizing() && size > 0;
boolean visibilityChanged = false;
View view = state.view;
int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
// 横屏和竖屏展示的为位置不一样,分别对应着设置的horizontalGravity和verticalGravity
int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity;
if (view == null) {
if (showView) {
// 为空会创建。相当于创建了Navigation 和Status View
// 即改变StatusBar/NavigationBar 实际上是改变了一个View 的颜色
state.view = view = new View(mContext);
view.setBackgroundColor(color);
view.setTransitionName(state.transitionName);
view.setId(state.id);
visibilityChanged = true;
view.setVisibility(INVISIBLE);
state.targetVisibility = VISIBLE;
LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight,
resolvedGravity);
lp.rightMargin = rightMargin;
addView(view, lp);
updateColorViewTranslations();
}
} else {
int vis = showView ? VISIBLE : INVISIBLE;
visibilityChanged = state.targetVisibility != vis;
state.targetVisibility = vis;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (lp.height != resolvedHeight || lp.width != resolvedWidth
|| lp.gravity != resolvedGravity || lp.rightMargin != rightMargin) {
lp.height = resolvedHeight;
lp.width = resolvedWidth;
lp.gravity = resolvedGravity;
lp.rightMargin = rightMargin;
view.setLayoutParams(lp);
}
if (showView) {
view.setBackgroundColor(color);
}
}
// 省略颜色修改无关代码
state.visible = show;
state.color = color;
}
从setStatusBarColor
(api 21以上)这个流程可以分析出来,Activity
中DecoeView
的StatusBar
和NavigationBar
对应的是一个普通的View
(系统中的StatusBar
和NavigationBar
都对应着一个Window
,StatusBar
中展示的电量、wifi等都是Window
中的View
,NavigationBar
中展示的返回键、Home键等也是Window
中的View
)。可以通过反射改变StatusBar
颜色和大小来验证(看源码也行的)DecoeView
对应着的是普通的View
。
/**
* 利用反射来设置StatusBar(DecorView中对应的StatusBar)颜色和高度(需要api21 以上)
*/
public void changeStatusBarColor2(View view) {
// reflect 改变
try {
Field field = getWindow().getDecorView().getClass().getDeclaredField("mStatusColorViewState");
field.setAccessible(true);
Object object = field.get(getWindow().getDecorView());
Field objectField = object.getClass().getDeclaredField("view");
objectField.setAccessible(true);
View view1 = (View) objectField.get(object);
Log.e("ChangeStatusBarColor", "status bar height = " + view1.getHeight());
view1.setBackgroundColor(0xffff0000);
ViewGroup.LayoutParams params =
view1.getLayoutParams();
params.height = 200;
view1.setLayoutParams(params);
} catch (Exception e) {
e.printStackTrace();
}
}
WindowManager.addView()
流程。
1.执行到WindowManagerImpl.addView()
(WindowManagerImpl
继承WindowManager
)。
// WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// 在Activity 中调用的话,这里的mParentWindow 就会是Activity 中的Window。
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
2.执行到WindowManagerGlobal.addView()
方法。
// WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
... // 省略很多代码
ViewRootImpl root;
synchronized (mLock) {
... // 省略很多代码
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view); // 在mViews中增加了需要add 的View
mRoots.add(root); // 在mRoots 中增加新的ViewRootImpl
mParams.add(wparams); // mParams 中增加新的WindowManager.LayoutParams
}
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
一个WindowManager
中对应着一系列的mViews
、mRoots
、mParams
,也就是WindowManager
管理着多个Window
,每一个Window
都对应着mViews[k]
、mRoots[k]
、mParams[k]
。如下所示。
// WindowManagerGlobal.java
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>();
3.执行到ViewRootImpl.setView()
方法。ViewRootImpl
相当于View
和ViewManager
之间的桥梁。里面的代码比较的长,会执行到ViewRootImpl.requestLayout()
。
4.执行到ViewRootImpl.requestLayout()
方法以及mWindowSession.addToDisplay
,其中ViewRootImpl.requestLayout()
会接着执行到了ViewRootImpl.scheduleTraversals()
。
// ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 这里通过mChoreographer.postCallback,最后相当于通过Handler发送了一个消息
//最后会执行到mTraversalRunnable的run
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
5.执行到TraversalRunnable.run()
,最后执行到了ViewRootImpl.doTraversal()
。
// ViewRootImpl.java
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
6.执行到ViewRootImpl.performTraversals()
。计算希望的大小,
判断是否是第一次,判断视图是否修改(例如:内容区域),判断Window 是否需要调整大小,判断是否改变了View 的可见性。最后会执行到ViewRootImpl.performMeasure()
、ViewRootImpl.performLayout()
、ViewRootImpl.performDraw()
7.ViewRootImpl.performMeasure()
会调用View.measure
对View进行测量;ViewRootImpl.performLayout()
会调用View.layout
对View进行布局。ViewRootImpl.performDraw()
会调用ViewRootImpl.draw
,然后会调用到ViewRootImpl.drawSoftware
,最后就会调用到View.draw
。这一系列的操作完成以后就会相当于展示创建了一个View,大小、位置以及视图也完全处理完毕。
8.第4步中执行到ViewRootImpl.requestLayout()
以后的过程已经分析完毕,相当于是对View 进行了测量、布局以及绘制。接下来执行mWindowSession.addToDisplay
。mWindowSession
对应的是一个IWindowSession.aidl
,Java 层实现的类是com.android.server.wm.Session
。
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
// mService 对应的是WindowManagerService
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
9.执行WindowManagerService.addWindow
。这里就是Window
的添加等,没有细看。
总结:通过WindowManager
对Window
的操作实际上就是对里面View
的操作,展示的也是里面View
的信息。
WindowManager.removeView()
流程。
这里有一个问题需要考虑一下,通过Activity.getWindowManager().removeView(View view)
,这里removeView的参数是什么?是Activity中设置的
View中的一个子
View`吗?
addView
第2步就有说明,这个View
其实是一个整体的View
,不是某个View
中的子View
,而是一个Window 中展示的View。
1.直接看到WindowManagerGlobal.removeView()
。
// WindowManagerGlobal.java
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
// 获取到view 对应的index,默认是-1
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
removeViewLocked(index, immediate);
if (curView == view) {
return;
}
throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
2.执行WindowManagerGlobal.removeViewLocked
// WindowManagerGlobal.java
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
if (view != null) {
InputMethodManager imm = InputMethodManager.getInstance();
// 执行remove 操作。
if (imm != null) {
imm.windowDismissed(mViews.get(index).getWindowToken());
}
}
// 执行die 操作。
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) {
// 将View 加入到mDyingViews 中。
mDyingViews.add(view);
}
}
}
总结:removeView
也是对View
的操作。
PopupWindow
显示流程
showAsDropDown(View anchor)
/showAtLocation(View parent, int gravity, int x, int y)
到 preparePopup(WindowManager.LayoutParams p)
,最后invokePopup(WindowManager.LayoutParams p)
,这里不再分析。
Dialog
显示流程
show()
,这里不再分析。
其它内容
1.查看当前Window的信息
。
Egos-MacBook-Pro:~ Egos$ adb shell dumpsys window windows | grep -E 'mCurrentFocus'
// Activity 对应的当前Window 信息
mCurrentFocus=Window{1cd90da2 u0 com.egos.samples/com.egos.samples.window.WindowActivity}
Egos-MacBook-Pro:~ Egos$ adb shell dumpsys window windows | grep -E 'mCurrentFocus'
// Activity 打开PopupWindow(使用Dialog 的时候效果也是一样的)之后对应的当前Window 信息
mCurrentFocus=Window{1ad2aefa u0 com.egos.samples/com.egos.samples.window.WindowActivity}
2.adb shell dumpsys window
查看当前所有的Window
信息,包括Window
的大小、位置。下面一个例子,拿中Window #3
来展示mAttrs
就展示了大小,mHasSurface
展示了起始位置。WindownManage.LayoutParams.mTitle 对应了名称。
Window #3 Window{914ba56 u0 com.egos.samples/com.egos.samples.window.WindowActivity}:
mDisplayId=0 stackId=1 mSession=Session{b853937 2930:u0a10102} mClient=android.os.BinderProxy@4d81c71
mOwnerUid=10102 mShowToOwnerOnly=true package=com.egos.samples appop=NONE
mAttrs=WM.LayoutParams{(0,0)(200x200) sim=#20 ty=2 fl=#0}
Requested w=200 h=200 mLayoutSeq=152
mHasSurface=true mShownPosition=[440,824] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{31dbad7 com.egos.samples/com.egos.samples.window.WindowActivity}:
Surface: shown=true layer=21015 alpha=1.0 rect=(440.0,824.0) 200.0 x 200.0
一个详细的例子。下面总共有9个Window(0,1,..8)
,可以看到NavigationBar
,StatusBar
(StatusBarWindowManager
管理着StatusBar Window
的)等其实都是Window
。也非常好验证,将StatusBar
向下滑动唤出全屏的通知栏,执行adb shell dumpsys window
会发现StatusBar 变成了全屏(从mAttrs
可以看出)。
PS:PhoneStatusBar.java
控制着StatusBar
和NavigationBar
。详情可以查看源码frameworks.base.packages.SystemUI
包下面的代码,包含了StatusBar
、NavigationBar
、截屏Window
、锁屏Window
等。
Egos-MacBook-Pro:aosp Egos$ adb shell dumpsys window
//.. 这里省略了很多信息,下面总共有9个Window(0,1,..8)
WINDOW MANAGER WINDOWS (dumpsys window windows)
Window #8 Window{c65e61c u0 NavigationBar}:
mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@d23238f
mOwnerUid=10023 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=2019 fl=#1840068 fmt=-3}
Requested w=1080 h=144 mLayoutSeq=271
mHasSurface=true mShownPosition=[0,1776] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{4b5dd83 NavigationBar}:
mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1
Surface: shown=true layer=211000 alpha=1.0 rect=(0.0,1776.0) 1080.0 x 144.0
Window #7 Window{6fa7c9a u0 StatusBar}:
mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@4f62d45
mOwnerUid=10023 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillx72) gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600}
Requested w=1080 h=72 mLayoutSeq=271
mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{83a4c32 StatusBar}:
mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1
Surface: shown=true layer=161000 alpha=1.0 rect=(0.0,0.0) 1080.0 x 72.0
Window #6 Window{7cba79f u0 KeyguardScrim}:
mDisplayId=0 stackId=0 mSession=Session{ddf9b54 1962:1000} mClient=android.view.ViewRootImpl$W@2c300ec
mOwnerUid=1000 mShowToOwnerOnly=false package=android appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=2029 fl=#1110900 pfl=0x1 fmt=-3 or=5 vsysui=0x3610000}
Requested w=1080 h=1776 mLayoutSeq=58
mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{b8b9c3d KeyguardScrim}:
mLastFreezeDuration=+2m59s819ms
Window #5 Window{401d23f u0 AssistPreviewPanel}:
mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@eb66e5e
mOwnerUid=10023 mShowToOwnerOnly=true package=com.android.systemui appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillx750) gr=#800053 sim=#31 ty=2033 fl=#1000118 fmt=-3 vsysui=0x700}
Requested w=0 h=0 mLayoutSeq=57
mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{10d4994 AssistPreviewPanel}:
mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
Window #4 Window{7af7b99 u0 DockedStackDivider}:
mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@ab9dce0
mOwnerUid=10023 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillx144) sim=#20 ty=2034 fl=#21840028 pfl=0x40 fmt=-3 vsysui=0x700}
Requested w=1080 h=144 mLayoutSeq=271
mPolicyVisibility=false mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false
mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{d3489e7 DockedStackDivider}:
mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
Window #3 Window{699ad0c u0 com.egos.samples/com.egos.samples.toast.ToastActivity}:
mDisplayId=0 stackId=1 mSession=Session{153e999 3360:u0a10102} mClient=android.os.BinderProxy@e9ef03f
mOwnerUid=10102 mShowToOwnerOnly=true package=com.egos.samples appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#120 ty=1 fl=#81810100 pfl=0x20000 wanim=0x1030465 vsysui=0x600 needsMenuKey=2}
Requested w=1080 h=1704 mLayoutSeq=271
mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{7b190d3 com.egos.samples/com.egos.samples.toast.ToastActivity}:
Surface: shown=true layer=21015 alpha=1.0 rect=(0.0,0.0) 1080.0 x 1920.0
Window #2 Window{df42f03 u0 com.android.launcher3/com.android.launcher3.Launcher}:
mDisplayId=0 stackId=0 mSession=Session{da8c367 2497:u0a10014} mClient=android.os.BinderProxy@820f3b2
mOwnerUid=10014 mShowToOwnerOnly=true package=com.android.launcher3 appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#120 ty=1 fl=#81910100 fmt=-2 wanim=0x1030465 vsysui=0x700 needsMenuKey=2}
Requested w=1080 h=1920 mLayoutSeq=227
mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{371f101 com.android.launcher3/com.android.launcher3.Launcher}:
mLastFreezeDuration=+2m59s941ms
mWallpaperX=0.0 mWallpaperY=0.5
Window #1 Window{2126153 u0 com.android.systemui/com.android.systemui.recents.RecentsActivity}:
mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@c0a3d42
mOwnerUid=10023 mShowToOwnerOnly=true package=com.android.systemui appop=NONE
mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#120 ty=1 fl=#81910100 pfl=0x24040 fmt=-3 vsysui=0x700 needsMenuKey=2}
Requested w=1080 h=1920 mLayoutSeq=187
mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{9f984a2 com.android.systemui/com.android.systemui.recents.RecentsActivity}:
mAnimating=true mLocalAnimating=false mAnimationIsEntrance=false mAnimation=null mStackClip=1
XForm: has=true hasLocal=false {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
mGlobalScale=1.0 mDsDx=1.0 mDtDx=0.0 mDsDy=0.0 mDtDy=1.0
Window #0 Window{c4fa95f u0 com.android.systemui.ImageWallpaper}:
mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@6adfe
mOwnerUid=10023 mShowToOwnerOnly=true package=com.android.systemui appop=NONE
mAttrs=WM.LayoutParams{(0,0)(1920x1920) gr=#800033 ty=2013 fl=#318 fmt=1 wanim=0x10302f2}
Requested w=1920 h=1920 mLayoutSeq=238
mIsImWindow=false mIsWallpaper=true mIsFloatingLayer=true mWallpaperVisible=false
mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
WindowStateAnimator{860a6e8 com.android.systemui.ImageWallpaper}:
Surface: shown=false layer=21000 alpha=1.0 rect=(0.0,0.0) 1920.0 x 1920.0
mLastFreezeDuration=+2m58s925ms
mWallpaperX=0.0 mWallpaperY=0.5
mCurConfiguration={1.0 310mcc260mnc [en_US] ldltr sw360dp w360dp h568dp 480dpi nrml port finger qwerty/v/v dpad/v s.6}
mHasPermanentDpad=false
mCurrentFocus=Window{699ad0c u0 com.egos.samples/com.egos.samples.toast.ToastActivity}
mFocusedApp=AppWindowToken{26954dc token=Token{2ae93ae ActivityRecord{9a6a429 u0 com.egos.samples/.toast.ToastActivity t169}}}
mInTouchMode=true mLayoutSeq=271
mLastDisplayFreezeDuration=0 due to Window{df42f03 u0 com.android.launcher3/com.android.launcher3.Launcher}
mLastWakeLockHoldingWindow=null mLastWakeLockObscuringWindow=Window{699ad0c u0 com.egos.samples/com.egos.samples.toast.ToastActivity}
Egos-MacBook-Pro:aosp Egos$
3.PhoneWindowManager.java
拦截键盘消息(比如home操作、截屏操作等)的处理类。
4.通过Android Studio
查看View Hierarchy
等信息。分析布局更加全面。
View Hierarchy:
com.android.internal.policy.DecorView{3afab2c V.E..... ... 0,0-1080,1920}
android.widget.LinearLayout{7fb79f5 V.E..... ... 0,0-1080,1776}
android.view.ViewStub{db9c38a G.E..... ... 0,0-0,0 #10203e8 android:id/action_mode_bar_stub}
android.widget.FrameLayout{8687dfb V.E..... ... 0,0-1080,1776}
android.support.v7.widget.ActionBarOverlayLayout{6024e18 V.E..... ... 0,0-1080,1776 #7f0c0055 app:id/decor_content_parent}
android.support.v7.widget.ContentFrameLayout{156c071 V.E..... ... 0,0-1080,1776 #1020002 android:id/content}
android.widget.LinearLayout{8f88e56 V.E..... ... 0,0-1080,1776}
android.support.v7.widget.AppCompatButton{9b6fed7 VFED..C. ... 0,240-635,384}
android.support.v7.widget.AppCompatButton{5da33c4 VFED..C. ... 0,384-659,528}
android.support.v7.widget.AppCompatButton{745f2ad VFED..C. ... 0,528-653,672}
android.support.v7.widget.ActionBarContainer{78739e2 V.ED.... ... 0,72-1080,240 #7f0c0056 app:id/action_bar_container}
android.support.v7.widget.Toolbar{f02b173 V.E..... ... 0,0-1080,168 #7f0c0057 app:id/action_bar}
android.support.v7.widget.AppCompatTextView{828c830 V.ED.... ... 48,43-280,124}
android.support.v7.widget.ActionMenuView{b7c0ca9 V.E..... ... 1080,0-1080,168}
android.support.v7.widget.ActionBarContextView{363122e G.E..... ... 0,0-0,0 #7f0c0058 app:id/action_context_bar}
android.view.View{e4cf1cf V.ED.... ... 0,1776-1080,1920 #1020030 android:id/navigationBarBackground}
android.view.View{d8a375c V.ED.... ... 0,0-1080,72 #102002f android:id/statusBarBackground}
最后
以上就是天真仙人掌为你收集整理的全面了解Window的全部内容,希望文章能够帮你解决全面了解Window所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复