SurfaceHolder callback throws when using SimpleExoPlayer from a background thread
See original GitHub issueThis is related to https://github.com/google/ExoPlayer/issues/8843
I create an exo player instance like this.
val playerThread = HandlerThread("video player thread")
playerThread.start()
val handler = Handler(playerThread.looper)
val player = SimpleExoPlayer.Builder(context).setLooper(playerThread.looper).build()
later I add some media items and set the surface
handler.post {
player.setVideoSurfaceHolder(surfaceView.holder)
val mediaItem: MediaItem = MediaItem.fromUri(Uri.parse(url))
playerInfo.player.setMediaItem(mediaItem)
playerInfo.player.prepare()
playerInfo.player.play()
}
I also tried just setting the surfaceView, but that gives the same results.
when detached from window
handler.post {
player.release()
playerThread.quitSafely()
}
Then I see a stack traces, e.g.
at com.google.android.exoplayer2.SimpleExoPlayer.verifyApplicationThread(SimpleExoPlayer.java:2028)
at com.google.android.exoplayer2.SimpleExoPlayer.getCurrentTimeline(SimpleExoPlayer.java:1670)
at com.google.android.exoplayer2.analytics.AnalyticsCollector.generateEventTime(AnalyticsCollector.java:863)
at com.google.android.exoplayer2.analytics.AnalyticsCollector.generateEventTime(AnalyticsCollector.java:912)
at com.google.android.exoplayer2.analytics.AnalyticsCollector.generateReadingMediaPeriodEventTime(AnalyticsCollector.java:920)
at com.google.android.exoplayer2.analytics.AnalyticsCollector.onSurfaceSizeChanged(AnalyticsCollector.java:492)
at com.google.android.exoplayer2.SimpleExoPlayer.maybeNotifySurfaceSizeChanged(SimpleExoPlayer.java:1962)
at com.google.android.exoplayer2.SimpleExoPlayer.access$4100(SimpleExoPlayer.java:92)
at com.google.android.exoplayer2.SimpleExoPlayer$ComponentListener.surfaceDestroyed(SimpleExoPlayer.java:2280)
at android.view.SurfaceView.notifySurfaceDestroyed(SurfaceView.java:1830)
at android.view.SurfaceView.updateSurface(SurfaceView.java:1126)
at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:306)
at android.view.View.dispatchDetachedFromWindow(View.java:20525)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3934)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3934)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3934)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5560)
at android.view.ViewGroup.removeViewAt(ViewGroup.java:5507)
at androidx.recyclerview.widget.RecyclerView$5.removeViewAt(RecyclerView.java:882)
at androidx.recyclerview.widget.ChildHelper.removeViewIfHidden(ChildHelper.java:386)
at androidx.recyclerview.widget.RecyclerView.removeAnimatingView(RecyclerView.java:1452)
at androidx.recyclerview.widget.RecyclerView$ItemAnimatorRestoreListener.onAnimationFinished(RecyclerView.java:12699)
at androidx.recyclerview.widget.RecyclerView$ItemAnimator.dispatchAnimationFinished(RecyclerView.java:13199)
at androidx.recyclerview.widget.SimpleItemAnimator.dispatchMoveFinished(SimpleItemAnimator.java:292)
at androidx.recyclerview.widget.DefaultItemAnimator$6.onAnimationEnd(DefaultItemAnimator.java:311)
at android.view.ViewPropertyAnimator$AnimatorEventListener.onAnimationEnd(ViewPropertyAnimator.java:1111)
at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:554)
at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1250)
at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1492)
at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)
at android.animation.AnimationHandler.access$100(AnimationHandler.java:37)
at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:970)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7660)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
From the previous bug it looks like because the window of the Surface view is on the main thread. Well of course it is, that’s the only thread it’s allowed to be on.
From what it looks like to me Exo Player doesn’t work when accessed on the non-ui thread when it’s using a surfaceview.
Worse results when using texture view as it doesn’t seem to work at all.
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (3 by maintainers)
Top Results From Across the Web
SurfaceHolder callback throws when using SimpleExoPlayer ...
SurfaceHolder callback throws when using SimpleExoPlayer from a background thread.
Read more >SimpleExoPlayer | Android Developers
Returns the Looper associated with the application thread that's used to access the player and on which player events are received.
Read more >SimpleExoPlayer (ExoPlayer library)
Modifier and Type Method Description
void decreaseDeviceVolume() Deprecated. Decreases the volume of the devi...
Clock getClock() Deprecated. Returns the Clock used for playb...
CueGroup getCurrentCues() Deprecated....
Read more >exoplayer.setThrowsWhenUsingWrongThread(false) is ...
1 Answer 1 ... setThrowsWhenUsingWrongThread() has become deprecated for the following reason according to the official documentation: "Disabling ...
Read more >mozilla-central: changeset 534055 ...
@throws ExoPlaybackException If an error occurs. ... For example a MediaSource - * may use a background thread to load data.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
In case someone sees this and wants to implement callbacks the way I did.
Wrapping the surface holder with what I have here is working for me. Of particular note,
DelegatingCallback
only implementsSufraceHolder.Callback
and notCallback2
, because that’s what exo implements. ImplementingCallback2
and delegating those methods will not work.Documentation is updated on dev-v2.