Merge pull request #2993 from Isira-Seneviratne/LifecycleService

Use LifecycleService.
This commit is contained in:
Bnyro 2023-02-08 10:00:58 +01:00 committed by GitHub
commit 793ad8e731
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 33 deletions

View File

@ -92,6 +92,7 @@ dependencies {
implementation libs.lifecycle.viewmodel
implementation libs.lifecycle.runtime
implementation libs.lifecycle.livedata
implementation libs.lifecycle.service
/* Testing */
androidTestImplementation libs.androidx.test.junit

View File

@ -3,7 +3,6 @@ package com.github.libretube.services
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Build
@ -13,10 +12,11 @@ import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.core.app.ServiceCompat
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import com.github.libretube.R
import com.github.libretube.api.JsonHelper
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.api.obj.Segment
import com.github.libretube.api.obj.SegmentData
import com.github.libretube.api.obj.Streams
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
@ -37,15 +37,15 @@ import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.PlaybackException
import com.google.android.exoplayer2.Player
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
/**
* Loads the selected videos audio in background mode with a notification area.
*/
class BackgroundMode : Service() {
class BackgroundMode : LifecycleService() {
/**
* VideoId of the video
*/
@ -171,7 +171,7 @@ class BackgroundMode : Service() {
seekToPosition: Long = 0,
keepQueue: Boolean = false
) {
CoroutineScope(Dispatchers.IO).launch {
lifecycleScope.launch(Dispatchers.IO) {
streams = runCatching {
RetrofitInstance.api.getStreams(videoId)
}.getOrNull() ?: return@launch
@ -186,7 +186,7 @@ class BackgroundMode : Service() {
PlayingQueue.updateCurrent(it)
}
handler.post {
withContext(Dispatchers.Main) {
playAudio(seekToPosition)
}
}
@ -292,17 +292,13 @@ class BackgroundMode : Service() {
* Sets the [MediaItem] with the [streams] into the [player]
*/
private fun setMediaItem() {
val streams = streams
streams ?: return
val uri = if (streams!!.audioStreams.orEmpty().isNotEmpty()) {
PlayerHelper.getAudioSource(
this,
streams!!.audioStreams!!
)
} else if (streams!!.hls != null) {
streams!!.hls
val uri = if (streams.audioStreams.isNotEmpty()) {
PlayerHelper.getAudioSource(this, streams.audioStreams)
} else {
return
streams.hls ?: return
}
val mediaItem = MediaItem.Builder()
@ -315,7 +311,7 @@ class BackgroundMode : Service() {
* fetch the segments for SponsorBlock
*/
private fun fetchSponsorBlockSegments() {
CoroutineScope(Dispatchers.IO).launch {
lifecycleScope.launch(Dispatchers.IO) {
runCatching {
val categories = PlayerHelper.getSponsorBlockCategories()
if (categories.isEmpty()) return@runCatching
@ -336,7 +332,7 @@ class BackgroundMode : Service() {
if (segmentData == null || segmentData!!.segments.isEmpty()) return
segmentData!!.segments.forEach { segment: Segment ->
segmentData!!.segments.forEach { segment ->
val segmentStart = (segment.segment[0] * 1000f).toLong()
val segmentEnd = (segment.segment[1] * 1000f).toLong()
val currentPosition = player?.currentPosition
@ -399,7 +395,8 @@ class BackgroundMode : Service() {
fun getService(): BackgroundMode = this@BackgroundMode
}
override fun onBind(p0: Intent?): IBinder {
override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
return binder
}

View File

@ -2,7 +2,6 @@ package com.github.libretube.services
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
@ -11,6 +10,8 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.util.set
import androidx.core.util.valueIterator
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import com.github.libretube.R
import com.github.libretube.api.CronetHelper
import com.github.libretube.api.RetrofitInstance
@ -40,9 +41,7 @@ import java.io.File
import java.net.HttpURLConnection
import java.net.SocketTimeoutException
import java.net.URL
import java.util.concurrent.Executors
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
@ -55,16 +54,15 @@ import okio.BufferedSink
import okio.buffer
import okio.sink
import okio.source
import java.util.concurrent.Executors
/**
* Download service with custom implementation of downloading using [HttpURLConnection].
*/
class DownloadService : Service() {
class DownloadService : LifecycleService() {
private val binder = LocalBinder()
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val jobMain = SupervisorJob()
private val scope = CoroutineScope(dispatcher + jobMain)
private val coroutineContext = dispatcher + SupervisorJob()
private lateinit var notificationManager: NotificationManager
private lateinit var summaryNotificationBuilder: NotificationCompat.Builder
@ -81,6 +79,7 @@ class DownloadService : Service() {
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
when (intent?.action) {
ACTION_DOWNLOAD_RESUME -> resume(intent.getIntExtra("id", -1))
ACTION_DOWNLOAD_PAUSE -> pause(intent.getIntExtra("id", -1))
@ -94,9 +93,11 @@ class DownloadService : Service() {
val audioQuality = intent.getStringExtra(IntentData.audioQuality)
val subtitleCode = intent.getStringExtra(IntentData.subtitleCode)
scope.launch {
lifecycleScope.launch(coroutineContext) {
try {
val streams = RetrofitInstance.api.getStreams(videoId)
val streams = withContext(Dispatchers.IO) {
RetrofitInstance.api.getStreams(videoId)
}
val thumbnailTargetFile = getDownloadFile(DownloadHelper.THUMBNAIL_DIR, fileName)
@ -153,7 +154,7 @@ class DownloadService : Service() {
Database.downloadDao().insertDownloadItem(item)
}.toInt()
scope.launch {
lifecycleScope.launch(coroutineContext) {
downloadFile(item)
}
}
@ -269,7 +270,8 @@ class DownloadService : Service() {
sourceByte.close()
con.disconnect()
}
} catch (_: Exception) { }
} catch (_: Exception) {
}
val completed = when {
totalRead < item.downloadSize -> {
@ -297,7 +299,7 @@ class DownloadService : Service() {
val downloadCount = downloadQueue.valueIterator().asSequence().count { it }
if (downloadCount >= DownloadHelper.getMaxConcurrentDownloads()) {
toastFromMainThread(getString(R.string.concurrent_downloads_limit_reached))
scope.launch {
lifecycleScope.launch(coroutineContext) {
_downloadFlow.emit(id to DownloadStatus.Paused)
}
return
@ -306,7 +308,7 @@ class DownloadService : Service() {
val downloadItem = awaitQuery {
Database.downloadDao().findDownloadItemById(id)
}
scope.launch {
lifecycleScope.launch(coroutineContext) {
downloadFile(downloadItem)
}
}
@ -468,9 +470,9 @@ class DownloadService : Service() {
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder {
val ids = intent?.getIntArrayExtra("ids")
ids?.forEach { id -> resume(id) }
override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
intent.getIntArrayExtra("ids")?.forEach { resume(it) }
return binder
}

View File

@ -45,6 +45,7 @@ square-leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary-andr
lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
lifecycle-livedata = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycle" }
lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service", version.ref = "lifecycle" }
room = { group = "androidx.room", name="room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
kotlinx-serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" }