From 93029ed1a165a6f579769f556746a4acfa118a63 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 31 Jul 2023 20:50:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/base/BaseService.kt | 10 ++-- .../io/legado/app/service/AudioPlayService.kt | 7 ++- .../app/service/BaseReadAloudService.kt | 29 +++++----- .../io/legado/app/service/CacheBookService.kt | 5 +- .../legado/app/service/CheckSourceService.kt | 3 +- .../io/legado/app/service/DownloadService.kt | 3 +- .../legado/app/service/ExportBookService.kt | 56 +++++++++++-------- .../app/service/HttpReadAloudService.kt | 14 +++-- 8 files changed, 75 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseService.kt b/app/src/main/java/io/legado/app/base/BaseService.kt index 66d003196..abee95a4f 100644 --- a/app/src/main/java/io/legado/app/base/BaseService.kt +++ b/app/src/main/java/io/legado/app/base/BaseService.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.os.IBinder import androidx.annotation.CallSuper import androidx.lifecycle.LifecycleService +import androidx.lifecycle.lifecycleScope import io.legado.app.R import io.legado.app.help.LifecycleHelp import io.legado.app.help.coroutine.Coroutine @@ -12,15 +13,13 @@ import io.legado.app.lib.permission.PermissionsCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.cancel import kotlinx.coroutines.isActive import kotlin.coroutines.CoroutineContext -abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() { +abstract class BaseService : LifecycleService() { fun execute( - scope: CoroutineScope = this, + scope: CoroutineScope = lifecycleScope, context: CoroutineContext = Dispatchers.IO, start: CoroutineStart = CoroutineStart.DEFAULT, executeContext: CoroutineContext = Dispatchers.Main, @@ -49,7 +48,6 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() { @CallSuper override fun onDestroy() { super.onDestroy() - cancel() LifecycleHelp.onServiceDestroy(this) } @@ -68,7 +66,7 @@ abstract class BaseService : LifecycleService(), CoroutineScope by MainScope() { .addPermissions(Permissions.POST_NOTIFICATIONS) .rationale(R.string.notification_permission_rationale) .onGranted { - if (isActive) { + if (lifecycleScope.isActive) { upNotification() } } diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index 06e7ec9ea..9b8aa7df0 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -15,6 +15,7 @@ import android.support.v4.media.MediaMetadataCompat import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.core.app.NotificationCompat +import androidx.lifecycle.lifecycleScope import androidx.media.AudioFocusRequestCompat import androidx.media3.common.PlaybackException import androidx.media3.common.Player @@ -341,7 +342,7 @@ class AudioPlayService : BaseService(), postEvent(EventBus.AUDIO_DS, timeMinute) upNotification() dsJob?.cancel() - dsJob = launch { + dsJob = lifecycleScope.launch { while (isActive) { delay(60000) if (!pause) { @@ -363,7 +364,7 @@ class AudioPlayService : BaseService(), */ private fun upPlayProgress() { upPlayProgressJob?.cancel() - upPlayProgressJob = launch { + upPlayProgressJob = lifecycleScope.launch { while (isActive) { AudioPlay.book?.let { //更新buffer位置 @@ -387,7 +388,7 @@ class AudioPlayService : BaseService(), val book = AudioPlay.book val bookSource = AudioPlay.bookSource if (book != null && bookSource != null) { - WebBook.getContent(this@AudioPlayService, bookSource, book, chapter) + WebBook.getContent(lifecycleScope, bookSource, book, chapter) .onSuccess { content -> if (content.isEmpty()) { toastOnUi("未获取到资源链接") diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 92f6c218f..d7b9fe2c8 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -15,6 +15,7 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.annotation.CallSuper import androidx.core.app.NotificationCompat +import androidx.lifecycle.lifecycleScope import androidx.media.AudioFocusRequestCompat import androidx.media.AudioManagerCompat import io.legado.app.R @@ -160,18 +161,20 @@ abstract class BaseReadAloudService : BaseService(), return super.onStartCommand(intent, flags, startId) } - private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) = launch(IO) { - this@BaseReadAloudService.pageIndex = pageIndex - textChapter = ReadBook.curTextChapter - val textChapter = textChapter ?: return@launch - nowSpeak = 0 - readAloudNumber = textChapter.getReadLength(pageIndex) + startPos - val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage) - contentList = textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos) - .split("\n") - .filter { it.isNotEmpty() } - launch(Main) { - if (play) play() else pageChanged = true + private fun newReadAloud(play: Boolean, pageIndex: Int, startPos: Int) { + lifecycleScope.launch(IO) { + this@BaseReadAloudService.pageIndex = pageIndex + textChapter = ReadBook.curTextChapter + val textChapter = textChapter ?: return@launch + nowSpeak = 0 + readAloudNumber = textChapter.getReadLength(pageIndex) + startPos + val readAloudByPage = getPrefBoolean(PreferKey.readAloudByPage) + contentList = textChapter.getNeedReadAloud(pageIndex, readAloudByPage, startPos) + .split("\n") + .filter { it.isNotEmpty() } + launch(Main) { + if (play) play() else pageChanged = true + } } } @@ -256,7 +259,7 @@ abstract class BaseReadAloudService : BaseService(), postEvent(EventBus.READ_ALOUD_DS, timeMinute) upNotification() dsJob?.cancel() - dsJob = launch { + dsJob = lifecycleScope.launch { while (isActive) { delay(60000) if (!pause) { diff --git a/app/src/main/java/io/legado/app/service/CacheBookService.kt b/app/src/main/java/io/legado/app/service/CacheBookService.kt index 3224cdc75..a4bd9a73e 100644 --- a/app/src/main/java/io/legado/app/service/CacheBookService.kt +++ b/app/src/main/java/io/legado/app/service/CacheBookService.kt @@ -2,6 +2,7 @@ package io.legado.app.service import android.content.Intent import androidx.core.app.NotificationCompat +import androidx.lifecycle.lifecycleScope import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.AppConst @@ -61,7 +62,7 @@ class CacheBookService : BaseService() { isRun = true CacheBook.successDownloadSet.clear() CacheBook.errorDownloadMap.clear() - launch { + lifecycleScope.launch { while (isActive) { delay(1000) notificationContent = CacheBook.downloadSummary @@ -142,7 +143,7 @@ class CacheBookService : BaseService() { private fun download() { downloadJob?.cancel() - downloadJob = launch(cachePool) { + downloadJob = lifecycleScope.launch(cachePool) { while (isActive) { if (!CacheBook.isRun) { CacheBook.stop(this@CacheBookService) diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt index 71f70ab72..fb9e878e3 100644 --- a/app/src/main/java/io/legado/app/service/CheckSourceService.kt +++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt @@ -2,6 +2,7 @@ package io.legado.app.service import android.content.Intent import androidx.core.app.NotificationCompat +import androidx.lifecycle.lifecycleScope import com.script.ScriptException import io.legado.app.R import io.legado.app.base.BaseService @@ -109,7 +110,7 @@ class CheckSourceService : BaseService() { synchronized(this) { processIndex++ } - launch(IO) { + lifecycleScope.launch(IO) { if (index < allIds.size) { val sourceUrl = allIds[index] appDb.bookSourceDao.getBookSource(sourceUrl)?.let { source -> diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index da7d31217..a3cfa8739 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -9,6 +9,7 @@ import android.content.IntentFilter import android.net.Uri import android.os.Environment import androidx.core.app.NotificationCompat +import androidx.lifecycle.lifecycleScope import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.AppConst @@ -147,7 +148,7 @@ class DownloadService : BaseService() { private fun checkDownloadState() { upStateJob?.cancel() - upStateJob = launch { + upStateJob = lifecycleScope.launch { while (isActive) { queryState() delay(1000) diff --git a/app/src/main/java/io/legado/app/service/ExportBookService.kt b/app/src/main/java/io/legado/app/service/ExportBookService.kt index fffde0dac..3e4641789 100644 --- a/app/src/main/java/io/legado/app/service/ExportBookService.kt +++ b/app/src/main/java/io/legado/app/service/ExportBookService.kt @@ -9,6 +9,7 @@ import android.os.Build import android.util.ArraySet import androidx.core.app.NotificationCompat import androidx.documentfile.provider.DocumentFile +import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition @@ -53,6 +54,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.ensureActive import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import me.ag2s.epublib.domain.Author import me.ag2s.epublib.domain.Date import me.ag2s.epublib.domain.EpubBook @@ -171,7 +173,7 @@ class ExportBookService : BaseService() { if (exportProgress.contains(bookUrl)) return exportProgress[bookUrl] = 0 waitExportBooks.remove(bookUrl) - exportJob = launch(IO) { + exportJob = lifecycleScope.launch(IO) { val book = appDb.bookDao.getBook(bookUrl) try { book ?: throw NoStackTraceException("获取${bookUrl}书籍出错") @@ -205,6 +207,12 @@ class ExportBookService : BaseService() { } } + private data class SrcData( + val chapterTitle: String, + val index: Int, + val src: String + ) + private suspend fun export(path: String, book: Book) { exportMsg.remove(book.bookUrl) postEvent(EventBus.EXPORT_BOOK, book.bookUrl) @@ -227,12 +235,16 @@ class ExportBookService : BaseService() { getAllContents(book) { text, srcList -> bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset))) srcList?.forEach { - val vFile = BookHelp.getImage(book, it.third) + val vFile = BookHelp.getImage(book, it.src) if (vFile.exists()) { DocumentUtils.createFileIfNotExist( doc, - "${it.second}-${MD5Utils.md5Encode16(it.third)}.jpg", - subDirs = arrayOf("${book.name}_${book.author}", "images", it.first) + "${it.index}-${MD5Utils.md5Encode16(it.src)}.jpg", + subDirs = arrayOf( + "${book.name}_${book.author}", + "images", + it.chapterTitle + ) )?.writeBytes(this, vFile.readBytes()) } } @@ -251,14 +263,14 @@ class ExportBookService : BaseService() { getAllContents(book) { text, srcList -> bookFile.appendText(text, Charset.forName(AppConfig.exportCharset)) srcList?.forEach { - val vFile = BookHelp.getImage(book, it.third) + val vFile = BookHelp.getImage(book, it.src) if (vFile.exists()) { FileUtils.createFileIfNotExist( file, "${book.name}_${book.author}", "images", - it.first, - "${it.second}-${MD5Utils.md5Encode16(it.third)}.jpg" + it.chapterTitle, + "${it.index}-${MD5Utils.md5Encode16(it.src)}.jpg" ).writeBytes(vFile.readBytes()) } } @@ -270,8 +282,8 @@ class ExportBookService : BaseService() { private suspend fun getAllContents( book: Book, - append: (text: String, srcList: ArrayList>?) -> Unit - ) { + append: (text: String, srcList: ArrayList?) -> Unit + ) = withContext(IO) { val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule() val contentProcessor = ContentProcessor.get(book.name, book.origin) val qy = "${book.name}\n${ @@ -285,7 +297,7 @@ class ExportBookService : BaseService() { append(qy, null) if (AppConfig.parallelExportBook) { val oc = - OrderCoroutine>?>>(AppConfig.threadCount) + OrderCoroutine?>>(AppConfig.threadCount) appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> oc.submit { getExportData(book, chapter, contentProcessor, useReplace) } } @@ -296,7 +308,7 @@ class ExportBookService : BaseService() { } } else { appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter -> - kotlin.coroutines.coroutineContext.ensureActive() + ensureActive() postEvent(EventBus.EXPORT_BOOK, book.bookUrl) exportProgress[book.bookUrl] = index val result = getExportData(book, chapter, contentProcessor, useReplace) @@ -311,7 +323,7 @@ class ExportBookService : BaseService() { chapter: BookChapter, contentProcessor: ContentProcessor, useReplace: Boolean - ): Pair>?> { + ): Pair?> { BookHelp.getContent(book, chapter).let { content -> val content1 = contentProcessor .getContent( @@ -326,13 +338,13 @@ class ExportBookService : BaseService() { ).toString() if (AppConfig.exportPictureFile) { //txt导出图片文件 - val srcList = arrayListOf>() + val srcList = arrayListOf() content?.split("\n")?.forEachIndexed { index, text -> val matcher = AppPattern.imgPattern.matcher(text) while (matcher.find()) { matcher.group(1)?.let { val src = NetworkUtils.getAbsoluteURL(chapter.url, it) - srcList.add(Triple(chapter.title, index, src)) + srcList.add(SrcData(chapter.title, index, src)) } } } @@ -594,12 +606,12 @@ class ExportBookService : BaseService() { contentModel: String, book: Book, epubBook: EpubBook - ) { + ) = withContext(IO) { //正文 val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule() val contentProcessor = ContentProcessor.get(book.name, book.origin) appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter -> - kotlin.coroutines.coroutineContext.ensureActive() + ensureActive() postEvent(EventBus.EXPORT_BOOK, book.bookUrl) exportProgress[book.bookUrl] = index BookHelp.getContent(book, chapter).let { content -> @@ -701,7 +713,7 @@ class ExportBookService : BaseService() { suspend fun export( path: String, book: Book - ) { + ) = withContext(IO) { exportProgress[book.bookUrl] = 0 exportMsg.remove(book.bookUrl) postEvent(EventBus.EXPORT_BOOK, book.bookUrl) @@ -729,7 +741,7 @@ class ExportBookService : BaseService() { progressBar += book.totalChapterNum.toDouble() / scope.size / 2 exportProgress[book.bookUrl] = progressBar.toInt() } - save2Drive(filename, epubBook, doc) { total, progress -> + save2Drive(filename, epubBook, doc) { total, _ -> //写入硬盘时更新进度条 progressBar += book.totalChapterNum.toDouble() / epubList.size / total / 2 postEvent(EventBus.EXPORT_BOOK, book.bookUrl) @@ -761,7 +773,7 @@ class ExportBookService : BaseService() { exportProgress[book.bookUrl]?.plus(book.totalChapterNum / scope.size) ?: 1 } - save2Drive(filename, epubBook, file) { total, progress -> + save2Drive(filename, epubBook, file) { total, _ -> //设置进度 progressBar += book.totalChapterNum.toDouble() / epubList.size / total / 2 postEvent(EventBus.EXPORT_BOOK, book.bookUrl) @@ -785,13 +797,13 @@ class ExportBookService : BaseService() { * @param epubBook 分割后的epub * @param epubBookIndex 分割后的epub序号 */ - private fun setEpubContent( + private suspend fun setEpubContent( contentModel: String, book: Book, epubBook: EpubBook, epubBookIndex: Int, updateProgress: (chapterList: MutableList, index: Int) -> Unit - ) { + ) = withContext(IO) { //正文 val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule() val contentProcessor = ContentProcessor.get(book.name, book.origin) @@ -813,7 +825,7 @@ class ExportBookService : BaseService() { if ((epubBookIndex + 1) * size > scope.size) scope.size else (epubBookIndex + 1) * size ) chapterList.forEachIndexed { index, chapter -> - coroutineContext.ensureActive() + ensureActive() updateProgress(chapterList, index) BookHelp.getContent(book, chapter).let { content -> var content1 = fixPic( diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 9e95ca914..0f65e4fcd 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -2,6 +2,7 @@ package io.legado.app.service import android.app.PendingIntent import android.net.Uri +import androidx.lifecycle.lifecycleScope import androidx.media3.common.MediaItem import androidx.media3.common.PlaybackException import androidx.media3.common.Player @@ -26,6 +27,7 @@ import io.legado.app.utils.printOnDebug import io.legado.app.utils.servicePendingIntent import io.legado.app.utils.toastOnUi import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -33,6 +35,7 @@ import kotlinx.coroutines.ensureActive import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext import okhttp3.Response import org.mozilla.javascript.WrappedException import java.io.File @@ -151,7 +154,10 @@ class HttpReadAloudService : BaseReadAloudService(), } } - private suspend fun getSpeakStream(httpTts: HttpTTS, speakText: String): InputStream? { + private suspend fun getSpeakStream( + httpTts: HttpTTS, + speakText: String + ): InputStream? = withContext(IO) { while (true) { try { val analyzeUrl = AnalyzeUrl( @@ -180,7 +186,7 @@ class HttpReadAloudService : BaseReadAloudService(), ensureActive() response.body!!.byteStream().let { stream -> downloadErrorNo = 0 - return stream + return@withContext stream } } catch (e: Exception) { when (e) { @@ -221,7 +227,7 @@ class HttpReadAloudService : BaseReadAloudService(), } } } - return null + return@withContext null } private fun md5SpeakFileName(content: String): String { @@ -294,7 +300,7 @@ class HttpReadAloudService : BaseReadAloudService(), private fun upPlayPos() { playIndexJob?.cancel() val textChapter = textChapter ?: return - playIndexJob = launch { + playIndexJob = lifecycleScope.launch { postEvent(EventBus.TTS_PROGRESS, readAloudNumber + 1) if (exoPlayer.duration <= 0) { return@launch