Simplify controller logic and catch cancellation exception
This commit is contained in:
parent
493ab65fc3
commit
a4a5938a38
2 changed files with 38 additions and 40 deletions
|
@ -9,9 +9,10 @@ import androidx.media3.session.MediaController
|
||||||
import androidx.media3.session.SessionToken
|
import androidx.media3.session.SessionToken
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
|
import com.simplemobiletools.musicplayer.extensions.getOrNull
|
||||||
import com.simplemobiletools.musicplayer.extensions.runOnPlayerThread
|
import com.simplemobiletools.musicplayer.extensions.runOnPlayerThread
|
||||||
import com.simplemobiletools.musicplayer.services.playback.PlaybackService
|
import com.simplemobiletools.musicplayer.services.playback.PlaybackService
|
||||||
import java.util.concurrent.CancellationException
|
import com.simplemobiletools.musicplayer.services.playback.PlaybackService.Companion.updatePlaybackInfo
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +20,7 @@ import java.util.concurrent.Executors
|
||||||
*/
|
*/
|
||||||
abstract class SimpleControllerActivity : SimpleActivity(), Player.Listener {
|
abstract class SimpleControllerActivity : SimpleActivity(), Player.Listener {
|
||||||
private val executorService by lazy {
|
private val executorService by lazy {
|
||||||
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(4))
|
MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var controllerFuture: ListenableFuture<MediaController>
|
private lateinit var controllerFuture: ListenableFuture<MediaController>
|
||||||
|
@ -39,38 +40,27 @@ abstract class SimpleControllerActivity : SimpleActivity(), Player.Listener {
|
||||||
releaseController()
|
releaseController()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getController(): MediaController? {
|
|
||||||
if (controllerFuture.isDone) {
|
|
||||||
val activeController = controllerFuture.get()
|
|
||||||
if (!activeController.isConnected) {
|
|
||||||
activeController.runOnPlayerThread {
|
|
||||||
release()
|
|
||||||
}
|
|
||||||
|
|
||||||
newControllerAsync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
controllerFuture.get()
|
|
||||||
} catch (e: CancellationException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun newControllerAsync() {
|
private fun newControllerAsync() {
|
||||||
controllerFuture = MediaController
|
controllerFuture = MediaController
|
||||||
.Builder(applicationContext, SessionToken(this, ComponentName(this, PlaybackService::class.java)))
|
.Builder(applicationContext, SessionToken(this, ComponentName(this, PlaybackService::class.java)))
|
||||||
.buildAsync()
|
.buildAsync()
|
||||||
|
|
||||||
controllerFuture.addListener({
|
controllerFuture.addListener({
|
||||||
getController()?.addListener(this)
|
controllerFuture.getOrNull()?.addListener(this)
|
||||||
}, MoreExecutors.directExecutor())
|
}, MoreExecutors.directExecutor())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun acquireController() {
|
private fun shouldCreateNewController(): Boolean {
|
||||||
if (controllerFuture.isDone && !controllerFuture.get().isConnected) {
|
return controllerFuture.isCancelled || controllerFuture.isDone && controllerFuture.getOrNull()?.isConnected == false
|
||||||
newControllerAsync()
|
}
|
||||||
|
|
||||||
|
private fun acquireController(callback: (() -> Unit)? = null) {
|
||||||
|
executorService.execute {
|
||||||
|
if (shouldCreateNewController()) {
|
||||||
|
newControllerAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
callback?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,33 +68,28 @@ abstract class SimpleControllerActivity : SimpleActivity(), Player.Listener {
|
||||||
MediaController.releaseFuture(controllerFuture)
|
MediaController.releaseFuture(controllerFuture)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun callOnPlayerThread(callback: MediaController.() -> Unit) {
|
|
||||||
getController()?.runOnPlayerThread {
|
|
||||||
callback(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [callback] is executed on a background player thread. When performing UI operations, callers should use [runOnUiThread].
|
* The [callback] is executed on a background player thread. When performing UI operations, callers should use [runOnUiThread].
|
||||||
*/
|
*/
|
||||||
fun withPlayer(callback: MediaController.() -> Unit) {
|
fun withPlayer(callback: MediaController.() -> Unit) {
|
||||||
if (controllerFuture.isDone && controllerFuture.get().isConnected) {
|
acquireController {
|
||||||
callOnPlayerThread(callback)
|
controllerFuture.getOrNull()?.runOnPlayerThread {
|
||||||
} else {
|
callback(this)
|
||||||
executorService.execute {
|
|
||||||
callOnPlayerThread(callback)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playMediaItems(mediaItems: List<MediaItem>, startIndex: Int = 0, startPosition: Long = 0) {
|
fun playMediaItems(mediaItems: List<MediaItem>, startIndex: Int = 0, startPosition: Long = 0, startActivity: Boolean = true) {
|
||||||
withPlayer {
|
withPlayer {
|
||||||
|
if (startActivity) {
|
||||||
|
startActivity(
|
||||||
|
Intent(this@SimpleControllerActivity, TrackActivity::class.java)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
setMediaItems(mediaItems, startIndex, startPosition)
|
setMediaItems(mediaItems, startIndex, startPosition)
|
||||||
prepare()
|
prepare()
|
||||||
play()
|
play()
|
||||||
startActivity(
|
|
||||||
Intent(this@SimpleControllerActivity, TrackActivity::class.java)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.simplemobiletools.musicplayer.extensions
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import java.util.concurrent.CancellationException
|
||||||
|
import java.util.concurrent.ExecutionException
|
||||||
|
|
||||||
|
fun <T> ListenableFuture<T>.getOrNull() = try {
|
||||||
|
get() as T
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
null
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
null
|
||||||
|
}
|
Loading…
Reference in a new issue