目录
结论
答案:无法复用
如果想知道为什么就继续,不想就可以关闭了。
分析
以下会借鉴多篇文章
从这里可以看到,surfaceTexture会被销毁掉,我便按照以上的方式尝试了一下。
但运行后出现报错:
Cannot setSurfaceTexture to a released SurfaceTexture
便找了
直接覆写 onSurfaceTextureDestoryed()方法,返回 false。
发现结果还是不可以。
这时我便看了源码 setSurfaceTexture 方法
/**
* Set the {@link SurfaceTexture} for this view to use. If a {@link
* SurfaceTexture} is already being used by this view, it is immediately
* released and not usable any more. The {@link
* SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
* called for the previous {@link SurfaceTexture}. Similarly, the {@link
* SurfaceTextureListener#onSurfaceTextureAvailable} callback is <b>not</b>
* called for the {@link SurfaceTexture} passed to setSurfaceTexture.
*
* The {@link SurfaceTexture} object must be detached from all OpenGL ES
* contexts prior to calling this method.
*
* @param surfaceTexture The {@link SurfaceTexture} that the view should use.
* @see SurfaceTexture#detachFromGLContext()
*/
public void setSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
throw new NullPointerException("surfaceTexture must not be null");
}
if (surfaceTexture == mSurface) {
throw new IllegalArgumentException("Trying to setSurfaceTexture to " +
"the same SurfaceTexture that's already set.");
}
if (surfaceTexture.isReleased()) {
throw new IllegalArgumentException("Cannot setSurfaceTexture to a " +
"released SurfaceTexture");
}
if (mSurface != null) {
nDestroyNativeWindow();
mSurface.release();
}
mSurface = surfaceTexture;
nCreateNativeWindow(mSurface);
/*
* If the view is visible and we already made a layer, update the
* listener in the new surface to use the existing listener in the view.
* Otherwise this will be called when the view becomes visible or the
* layer is created
*/
if (((mViewFlags & VISIBILITY_MASK) == VISIBLE) && mLayer != null) {
mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
}
mUpdateSurface = true;
invalidateParentIfNeeded();
}
抛异常是根据 surfaceTexture.isReleased() 来判断的,
继续追溯
/**
* {@code release()} frees all the buffers and puts the SurfaceTexture into the
* 'abandoned' state. Once put in this state the SurfaceTexture can never
* leave it. When in the 'abandoned' state, all methods of the
* {@code IGraphicBufferProducer} interface will fail with the {@code NO_INIT}
* error.
* <p>
* Note that while calling this method causes all the buffers to be freed
* from the perspective of the the SurfaceTexture, if there are additional
* references on the buffers (e.g. if a buffer is referenced by a client or
* by OpenGL ES as a texture) then those buffer will remain allocated.
* <p>
* Always call this method when you are done with SurfaceTexture. Failing
* to do so may delay resource deallocation for a significant amount of
* time.
*
* @see #isReleased()
*/
public void release() {
nativeRelease();
}
/**
* Returns {@code true} if the SurfaceTexture was released.
*
* @see #release()
*/
public boolean isReleased() {
return nativeIsReleased();
}
isReleased() 会返回 nativeIsReleased() ; 是通过native层实现的。
发现 release() 也是同样调用。
便查看 release() 在何处调用
private void releaseSurfaceTexture() {
if (mSurface != null) {
boolean shouldRelease = true;
if (mListener != null) {
shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
}
synchronized (mNativeWindowLock) {
nDestroyNativeWindow();
}
if (shouldRelease) {
mSurface.release();
}
mSurface = null;
mHadSurface = true;
}
}
发现是根据变量 shouldRelease 来判断,而 shouldRelease 又是根据 onSurfaceTextureDestroyed() 返回值。
这和我上边覆写onSurfaceTextureDestroyed() 返回 false是同样的,
说明 shouldRelease == false 也是会导致GLTextureView无法复用。
继续追溯 releaseSurfaceTexture() 会在哪里调用?
/** @hide */
@Override
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
protected void onDetachedFromWindowInternal() {
destroyHardwareLayer();
releaseSurfaceTexture();
super.onDetachedFromWindowInternal();
}
你会发现是在 onDetachedFromWindowInternal()被调用,而这个是只有在你窗口被移除的时候才会调用。
所以,只要你把view不显示,就会调用 releaseSurfaceTexture(),onDetachedFromWindowInternal() 还注解 @UnsupportedAppUsage,所以对无法其进行覆写。
结论:GLTextureView无法复用。