问题列表
- 打开其他页面返回当前页面 GLSurfaceView会有短暂黑屏
- 按HOME键回到后台再切换回来 GLSurfaceView会有短暂黑屏
分析
以上问题 总结下就是回到后台后再切换到前台, GLSurfaceView会有短暂黑屏
提出问题
1.GLSurfaceView 回到后台做了什么
2.GLSurfaceView 回到前台做了什么
GLSurfaceView 回到后台以及前台,那么关注onWindowVisibilityChanged 就可以了,我们看下相关源码
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
updateWindow(false, false);
}
protected void updateWindow(boolean force, boolean redrawNeeded) {
if (!mHaveFrame) {
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) {
mTranslator = viewRoot.mTranslator;
}
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
getLocationInWindow(mLocation);
final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| mLeft != mLocation[0] || mTop != mLocation[1]
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged
+ " left=" + (mLeft != mLocation[0])
+ " top=" + (mTop != mLocation[1]));
try {
final boolean visible = mVisible = mRequestedVisible;
mLeft = mLocation[0];
mTop = mLocation[1];
mWidth = myWidth;
mHeight = myHeight;
mFormat = mRequestedFormat;
// Scaling/Translate window's layout here because mLayout is not used elsewhere.
// Places the window relative
mLayout.x = mLeft;
mLayout.y = mTop;
mLayout.width = getWidth();
mLayout.height = getHeight();
if (mTranslator != null) {
mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
}
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
mLayout.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
}
mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
if (mWindow == null) {
Display display = getDisplay();
mWindow = new MyWindow(this);
mLayout.type = mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
mStableInsets);
}
boolean realSizeChanged;
boolean reportDrawNeeded;
int relayoutResult;
mSurfaceLock.lock();
try {
mUpdateWindowNeeded = false;
reportDrawNeeded = mReportDrawNeeded;
mReportDrawNeeded = false;
mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE,
WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
mNewSurface);
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportDrawNeeded = true;
}
if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
mSurfaceFrame.right = mWinFrame.width();
mSurfaceFrame.bottom = mWinFrame.height();
} else {
float appInvertedScale = mTranslator.applicationInvertedScale;
mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
}
final int surfaceWidth = mSurfaceFrame.right;
final int surfaceHeight = mSurfaceFrame.bottom;
realSizeChanged = mLastSurfaceWidth != surfaceWidth
|| mLastSurfaceHeight != surfaceHeight;
mLastSurfaceWidth = surfaceWidth;
mLastSurfaceHeight = surfaceHeight;
} finally {
mSurfaceLock.unlock();
}
try {
redrawNeeded |= creating | reportDrawNeeded;
SurfaceHolder.Callback callbacks[] = null;
final boolean surfaceChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
// 重点关注点1 在window 不显示时,调用了SurfaceHolder的surfaceDestroyed方法 并把mSurfaceCreated=false
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
}
}
mSurface.transferFrom(mNewSurface);
if (visible && mSurface.isValid()) {
// 重点关注点2 在window 显示时,会触发这里,先surfaceCreated 后surfaceChanged
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
+ " w=" + myWidth + " h=" + myHeight);
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
}
}
if (redrawNeeded) {
if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
if (c instanceof SurfaceHolder.Callback2) {
((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
mSurfaceHolder);
}
}
}
}
} finally {
mIsCreating = false;
if (redrawNeeded) {
if (DEBUG) Log.i(TAG, "finishedDrawing");
mSession.finishDrawing(mWindow);
}
mSession.performDeferredDestroy(mWindow);
}
} catch (RemoteException ex) {
}
if (DEBUG) Log.v(
TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
" w=" + mLayout.width + " h=" + mLayout.height +
", frame=" + mSurfaceFrame);
}
}
上边列出了两个重点关注点 ,1是回到后台的逻辑,2是回到前台的逻辑
那么问题的原因就算找到了,找到了的话如何解决。
解决
首先这里回到后台回收是为了回收部分资源,让性能更好利用起来,但是出现了一些体验问题
不建议我们总是违背系统意愿做自己想做的事
解决方案就是不触发回收,如何不触发回收,重写onWindowVisibilityChanged,如下
```
override fun onWindowVisibilityChanged(visibility: Int) {
super.onWindowVisibilityChanged(View.VISIBLE)
// 以下是优化建议,在显示不显示时处理一下后台资源
if (visibility == View.VISIBLE) {
ResumeThread()
} else {
SuspendThread()
}
}
```