在Android开发过程中,经常需要获取Window或某个View的可见性变化时机,以便在View的Visibility变化时进行相应的处理。目前,比较常用的判断View可见性时机的回调有
- onWindowVisibilityChanged
- onVisibilityChanged
- OnAttachStateChangeListener#onViewAttachedToWindow
一、onWindowVisibilityChanged
/**
* Called when the window containing has change its visibility
* (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note
* that this tells you whether or not your window is being made visible
* to the window manager; this does <em>not</em> tell you whether or not
* your window is obscured by other windows on the screen, even if it
* is itself visible.
*
* @param visibility The new visibility of the window.
*/
protected void onWindowVisibilityChanged(@Visibility int visibility) {
if (visibility == VISIBLE) {
initialAwakenScrollBars();
}
}
由方法注释可知,它是在窗口可见性改变时调用,而且注意这只是在Window对WindowManager可见时调用,并不是告知你当前可见的Window是否被遮挡。
查看代码,发现其调用位置有3处,添加时在performTraversals
方法中(代码有省略),Activity onStop生命周期会remove掉DecorView和对应的Window,在removeView
方法中会调用dispatchDetachedFromWindow
方法,该方法内又会调用onWindowVisibilityChanged
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
......
final int viewVisibility = getHostVisibility();
final boolean viewVisibilityChanged = !mFirst
&& (mViewVisibility != viewVisibility || mNewSurfaceNeeded
// Also check for possible double visibility update, which will make current
// viewVisibility value equal to mViewVisibility and we may miss it.
|| mAppVisibilityChanged);
mAppVisibilityChanged = false;
final boolean viewUserVisibilityChanged = !mFirst &&
((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
......
if (mFirst) {
......
// We used to use the following condition to choose 32 bits drawing caches:
// PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
// However, windows are now always 32 bits by default, so choose 32 bits
mAttachInfo.mUse32BitDrawingCache = true;
mAttachInfo.mWindowVisibility = viewVisibility;
mAttachInfo.mRecomputeGlobalAttributes = false;
mLastConfigurationFromResources.setTo(config);
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
// Set the layout direction if it has not been set before (inherit is the default)
if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
host.setLayoutDirection(config.getLayoutDirection());
}
/**
* ①
*/
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
} else {
......
}
}
if (viewVisibilityChanged) {
mAttachInfo.mWindowVisibility = viewVisibility;
/**
* ②
*/
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewUserVisibilityChanged) {
host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);