The problem

When using mediaPlay+TextureView to play and display the video, on the redmi note4x, cut the background while the video is playing and return to a black screen in the video area, indicating that the audio can continue to play. There is no such problem when playing on other phones.

code

class VideoView(context: Context, attrs: AttributeSet? = null) : TextureView(context, attrs), TextureView.SurfaceTextureListener, LifecycleObserver {

    private var mediaPlayer: MediaPlayer? = null
    private var surface: Surface? = null
    private var resId: Int = 0

    init {
        if (context is FragmentActivity) {
            context.lifecycle.addObserver(this)
        }
        surfaceTextureListener = this
    }

    fun setVideoId(resId: Int) {
        this.resId = resId
        mediaPlayer = MediaPlayer.create(context, resId)
    }

    fun start(a){ mediaPlayer? .start() }fun release(a){ mediaPlayer? .apply {this.stop()
            this.release() } surfaceTexture? .release() mediaPlayer =null
    }

    private fun initSurface(a){ surface = Surface(surfaceTexture) mediaPlayer? .setSurface(surface) }@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy(a) {
        release()
        if (context is FragmentActivity) {
            (context as FragmentActivity).lifecycle.removeObserver(this)}}override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
        initSurface()
    }

    override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {}
    override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
		release()
        return false
    }

    override fun onSurfaceTextureUpdated(surface: SurfaceTexture){}}Copy the code

Problem analysis

In red rice onSurfaceTextureDestroyed note 4 x when they cut the background on your phone call, because in the onSurfaceTextureDestroyed will call release () in the release () will be the release of players and resources, So after return to front desk call onSurfaceTextureAvailable because the player is empty, so show black screen.1. Redmi Note 4X call stackRed rice note cut backstage as shown belowCall stack breakpoint print stack information

onSurfaceTextureDestroyed:91, MyVideoView (com.bytedance.minddance.android.devicecheck.view)
destroySurface:231, TextureView (android.view)
destroyHardwareResources:364, TextureView (android.view)
destroyResources:518, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyResources:525, ThreadedRenderer (android.view)
destroyHardwareResources:513, ThreadedRenderer (android.view)
setWindowStopped:1186, ViewRootImpl (android.view)
setStoppedState:639, WindowManagerGlobal (android.view)
performStop:7023, Activity (android.app)
performStopActivityInner:3965, ActivityThread (android.app)
handleStopActivity:4023, ActivityThread (android.app)
-wrap25:-1, ActivityThread (android.app)
handleMessage:1577, ActivityThread$H (android.app)
dispatchMessage:102, Handler (android.os)
loop:165, Looper (android.os)
main:6375, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:883, ZygoteInit$MethodAndArgsCaller (com.android.internal.os)
main:773, ZygoteInit (com.android.internal.os)
Copy the code

Android 7.0.0_r6: Textureview.java

private void destroySurface(a) {
        if(mLayer ! =null) {
            mLayer.detachSurfaceTexture();

            boolean shouldRelease = true;
            if(mListener ! =null) {
                shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
            }

            synchronized (mNativeWindowLock) {
                nDestroyNativeWindow();
            }

            mLayer.destroy();
            if (shouldRelease) mSurface.release();
            mSurface = null;
            mLayer = null;

            // Make sure if/when new layer gets re-created, transform matrix will
            // be re-applied.
            mMatrixChanged = true;
            mHadSurface = true; }}Copy the code

MListener. OnSurfaceTextureDestroyed (mSurface) method is in destroySurface () call. After cut the background call stopActivity in note 4 x will call destorySurface method, lead to mListener. OnSurfaceTextureDestroyed (mSurface) calls and released mediaPlay related resources, The black screen is displayed only after cutting back to the foreground. Note: A simultaneous look at other versions of TextureView did not find the destroySurface method. That is to say, it is only on this version.

2. Call stack of other mobile phonesHuawei mobile phone only when to exit the current activity will call onSurfaceTextureDestroyed method,

Below is the call stack for exit

onSurfaceTextureDestroyed:91, MyVideoView (com.bytedance.minddance.android.devicecheck.view)
releaseSurfaceTexture:261, TextureView (android.view)
onDetachedFromWindowInternal:232, TextureView (android.view)
dispatchDetachedFromWindow:19819, View (android.view)
dispatchDetachedFromWindow:4010, ViewGroup (android.view)
dispatchDetachedFromWindow:4010, ViewGroup (android.view)
dispatchDetachedFromWindow:4010, ViewGroup (android.view)
dispatchDetachedFromWindow:4010, ViewGroup (android.view)
removeViewInternal:5653, ViewGroup (android.view)
removeViewInternal:5624, ViewGroup (android.view)
removeView:5555, ViewGroup (android.view)
moveToState:1248, FragmentManager (androidx.fragment.app)
moveToState:1354, FragmentManager (androidx.fragment.app)
moveFragmentToExpectedState:1432, FragmentManager (androidx.fragment.app)
moveToState:1495, FragmentManager (androidx.fragment.app)
dispatchStateChange:2617, FragmentManager (androidx.fragment.app)
dispatchDestroy:2601, FragmentManager (androidx.fragment.app)
dispatchDestroy:330, FragmentController (androidx.fragment.app)
onDestroy:365, FragmentActivity (androidx.fragment.app)
onDestroy:242, AppCompatActivity (androidx.appcompat.app)
onDestroy:435, BaseActivity (com.bytedance.minddance.android.ui.base)
onDestroy:309, BaseSlideBackActivity (com.bytedance.minddance.android.ui.base)
performDestroy:8349, Activity (android.app)
callActivityOnDestroy:1355, Instrumentation (android.app)
performDestroyActivity:5670, ActivityThread (android.app)
handleDestroyActivity:5715, ActivityThread (android.app)
execute:44, DestroyActivityItem (android.app.servertransaction)
executeLifecycleState:190, TransactionExecutor (android.app.servertransaction)
execute:105, TransactionExecutor (android.app.servertransaction)
handleMessage:2473, ActivityThread$H (android.app)
dispatchMessage:110, Handler (android.os)
loop:219, Looper (android.os)
main:8349, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:513, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:1055, ZygoteInit (com.android.internal.os)
Copy the code

Huawei mobile phone will not call to onSurfaceTextureDestroyed method in the background.

4. Solutions

The problem is due to the above call onSurfaceTextureDestroyed method when cutting the background, and in onSurfaceTextureDestroyed stopPlayback mediaPlay for the release, black screen cut back to the front desk, The solution is to remove the onSurfaceTextureDestroyed release () method. Summary Android system version android-7.0.0_R6 this version of the background will have this problem.

reference

1, stackoverflow.com/questions/6…

2, stackoverflow.com/questions/3…

3, developer.android.com/reference/a…

4, developer.android.com/guide/topic…

5, developer.android.com/reference/a…

6, blog.mindorks.com/using-media…