3

I have a third party library that periodically queries my video player (ExoPlayer) for information such as current position in the video. This third party library runs on a background thread. Problem is, the ExoPlayer instance is not allowed to be accessed by a background thread.

One of my ideas was to use coroutines to force a switch to the main thread before accessing the ExoPlayer instance. Something like this (note that this is called from multiple places, both on main and background threads):

suspend fun getCurrentPosition(): Long { if (Looper.myLooper() != Looper.getMainLooper()) { // On a background thread, switch to main thread and return current position return withContext(Dispatchers.Main) { exoPlayerInstance.currentPosition } } else { // Already on main thread, no need to switch threads return exoPlayerInstance.currentPosition } } 

Then I would call this with runBlocking like so:

runBlocking { videoPlayerWrapper.getCurrentPosition() } 

runBlocking is used because the third party library expects an instant result.

This works sometimes but other times my app is completely locking up. Any idea what might be wrong? Any alternative solutions?

2 Answers 2

2

runBlocking is a suspend function that blocks current thread until coroutine launched is completed. I guess that you are blocking main thread with this call. I suggest you to use a function like this.

 fun getCurrentPosition() = runBlocking(Dispatchers.Main.immediate) { exoPlayerInstance.currentPosition } 

The Dispatchers.Main.immediate switches context only if current thread is not the main thread.

Sign up to request clarification or add additional context in comments.

Comments

0

Then I would call this with runBlocking like so:

runBlocking { videoPlayerWrapper.getCurrentPosition() }

By definition runBlocking will block the current Thread until the coroutine completes. From the runBlocking docs:

Runs a new coroutine and blocks the current thread interruptibly until its completion. This function should not be used from a coroutine. It is designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests.

This effectively means that your UI will freeze if you are calling runBlocking from the main Thread. My guess is that sometimes videoPlayerWrapper.getCurrentPosition() returns fast enough for you not to notice that is actually blocking.

This third party library runs on a background thread. Problem is, the ExoPlayer instance is not allowed to be accessed by a background thread.

It seems to me that there is a design flaw here. Rather than the library trying to get a hold of the Exoplayer instance, the library should establish a contract for the consumer to provide the position. If using coroutines, the library could require a Flow<Int> that emits the current position as the position changes.

9 Comments

Agree on the library flaw, however it's out of my hands. The library requires you to pass it an implementation of an interface which has method definitions such as: "fun getVideoPosition(): Long". I still don't understand why my UI thread is deadlocking with the above code.
Where are you calling runBlocking{} from? From what Thread?
I do not think the Looper check adds much value since withContext(Dispatchers.Main) makes sure you are switched to the main Thread and if you already are on the main Thread there is no context switch. What I mean is that returning withContext(Dispatchers.Main){exoPlayerInstance.currentPosition} should be enough. As far as why the UI is freezing, again, runBlocking{} is intended to be used by main functions or during tests since it blocks the Thread from which it is called.
Changing my answer... runBlocking might be called from both background and main. I'll have to double check in the morning. Definitely at least from the background though.
I understand that runBlocking blocks the current thread. But it should only block until the work has completed. And there's really no blocking work here. It's just returning a value.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.