kunfei 3 лет назад
Родитель
Сommit
a14a3cfdd8
34 измененных файлов с 168 добавлено и 125 удалено
  1. 1 9
      app/src/main/java/io/legado/app/base/BaseActivity.kt
  2. 5 3
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  3. 4 3
      app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt
  4. 10 3
      app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt
  5. 2 1
      app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt
  6. 2 1
      app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkActivity.kt
  7. 4 3
      app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt
  8. 1 2
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceDialog.kt
  9. 1 3
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeChapterSourceDialog.kt
  10. 14 13
      app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt
  11. 16 11
      app/src/main/java/io/legado/app/ui/book/import/local/ImportBookViewModel.kt
  12. 8 9
      app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookActivity.kt
  13. 7 5
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  14. 4 3
      app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageActivity.kt
  15. 12 11
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  16. 21 8
      app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
  17. 3 2
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt
  18. 3 2
      app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugActivity.kt
  19. 4 3
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  20. 5 4
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  21. 1 3
      app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt
  22. 2 1
      app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleActivity.kt
  23. 2 1
      app/src/main/java/io/legado/app/ui/dict/rule/DictRuleActivity.kt
  24. 3 2
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  25. 1 1
      app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt
  26. 5 2
      app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt
  27. 2 1
      app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt
  28. 5 3
      app/src/main/java/io/legado/app/ui/rss/article/RssSortActivity.kt
  29. 2 1
      app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesActivity.kt
  30. 2 1
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  31. 2 1
      app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt
  32. 3 2
      app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt
  33. 5 2
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt
  34. 6 5
      app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubActivity.kt

+ 1 - 9
app/src/main/java/io/legado/app/base/BaseActivity.kt

@@ -25,9 +25,6 @@ import io.legado.app.lib.theme.backgroundColor
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.ui.widget.TitleBar
 import io.legado.app.utils.*
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.cancel
 
 
 abstract class BaseActivity<VB : ViewBinding>(
@@ -36,7 +33,7 @@ abstract class BaseActivity<VB : ViewBinding>(
     private val toolBarTheme: Theme = Theme.Auto,
     private val transparent: Boolean = false,
     private val imageBg: Boolean = true
-) : AppCompatActivity(), CoroutineScope by MainScope() {
+) : AppCompatActivity() {
 
     protected abstract val binding: VB
 
@@ -97,11 +94,6 @@ abstract class BaseActivity<VB : ViewBinding>(
         setupSystemBar()
     }
 
-    override fun onDestroy() {
-        super.onDestroy()
-        cancel()
-    }
-
     abstract fun onActivityCreated(savedInstanceState: Bundle?)
 
     final override fun onCreateOptionsMenu(menu: Menu): Boolean {

+ 5 - 3
app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt

@@ -6,7 +6,9 @@ import io.legado.app.data.entities.BookSource
 import io.legado.app.data.entities.BookSourcePart
 import io.legado.app.utils.cnCompare
 import io.legado.app.utils.splitNotBlank
+import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 
 @Dao
@@ -293,18 +295,18 @@ interface BookSourceDao {
     fun flowGroups(): Flow<List<String>> {
         return flowGroupsUnProcessed().map { list ->
             dealGroups(list)
-        }
+        }.flowOn(IO)
     }
 
     fun flowExploreGroups(): Flow<List<String>> {
         return flowExploreGroupsUnProcessed().map { list ->
             dealGroups(list)
-        }
+        }.flowOn(IO)
     }
 
     fun flowEnabledGroups(): Flow<List<String>> {
         return flowEnabledGroupsUnProcessed().map { list ->
             dealGroups(list)
-        }
+        }.flowOn(IO)
     }
 }

+ 4 - 3
app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt

@@ -6,6 +6,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.view.ViewGroup
 import androidx.appcompat.widget.SearchView
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.BaseActivity
 import io.legado.app.base.adapter.ItemViewHolder
@@ -126,7 +127,7 @@ class ReadRecordActivity : BaseActivity<ActivityReadRecordBinding>() {
     }
 
     private fun initAllTime() {
-        launch {
+        lifecycleScope.launch {
             val allTime = withContext(IO) {
                 appDb.readRecordDao.allTime
             }
@@ -135,7 +136,7 @@ class ReadRecordActivity : BaseActivity<ActivityReadRecordBinding>() {
     }
 
     private fun initData(searchKey: String? = null) {
-        launch {
+        lifecycleScope.launch {
             val readRecords = withContext(IO) {
                 appDb.readRecordDao.search(searchKey ?: "").let { records ->
                     when (sortMode) {
@@ -181,7 +182,7 @@ class ReadRecordActivity : BaseActivity<ActivityReadRecordBinding>() {
             binding.apply {
                 root.setOnClickListener {
                     val item = getItem(holder.layoutPosition) ?: return@setOnClickListener
-                    launch {
+                    lifecycleScope.launch {
                         val book = withContext(IO) {
                             appDb.bookDao.findByName(item.bookName).firstOrNull()
                         }

+ 10 - 3
app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt

@@ -5,6 +5,7 @@ import android.os.Build
 import android.os.Bundle
 import androidx.activity.viewModels
 import androidx.documentfile.provider.DocumentFile
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.constant.AppConst
@@ -16,13 +17,19 @@ import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.PermissionsCompat
 import io.legado.app.ui.book.read.ReadBookActivity
 import io.legado.app.ui.file.HandleFileContract
-import io.legado.app.utils.*
+import io.legado.app.utils.FileUtils
+import io.legado.app.utils.checkWrite
+import io.legado.app.utils.getFile
+import io.legado.app.utils.isContentScheme
+import io.legado.app.utils.readUri
+import io.legado.app.utils.showDialogFragment
+import io.legado.app.utils.startActivity
+import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import splitties.init.appCtx
-
 import java.io.File
 import java.io.FileOutputStream
 
@@ -147,7 +154,7 @@ class FileAssociationActivity :
     }
 
     private fun importBook(treeUri: Uri, uri: Uri) {
-        launch {
+        lifecycleScope.launch {
             runCatching {
                 withContext(IO) {
                     if (treeUri.isContentScheme()) {

+ 2 - 1
app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt

@@ -10,6 +10,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.widget.SeekBar
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.constant.BookType
@@ -195,7 +196,7 @@ class AudioPlayActivity :
             viewModel.changeTo(source, book, toc)
         } else {
             AudioPlay.stop(this)
-            launch {
+            lifecycleScope.launch {
                 withContext(IO) {
                     AudioPlay.book?.migrateTo(book, toc)
                     book.removeType(BookType.updateError)

+ 2 - 1
app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkActivity.kt

@@ -4,6 +4,7 @@ import android.os.Bundle
 import android.view.Menu
 import android.view.MenuItem
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.data.appDb
@@ -33,7 +34,7 @@ class AllBookmarkActivity : VMBaseActivity<ActivityAllBookmarkBinding, AllBookma
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         initView()
-        launch {
+        lifecycleScope.launch {
             appDb.bookmarkDao.flowAll().collect {
                 adapter.setItems(it)
             }

+ 4 - 3
app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt

@@ -7,6 +7,7 @@ import android.view.MenuItem
 import android.view.View
 import androidx.activity.viewModels
 import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import com.google.android.material.textfield.TextInputLayout
 import io.legado.app.R
@@ -87,7 +88,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         groupId = intent.getLongExtra("groupId", -1)
-        launch {
+        lifecycleScope.launch {
             binding.titleBar.subtitle = withContext(IO) {
                 appDb.bookGroupDao.getByID(groupId)?.groupName
                     ?: getString(R.string.no_group)
@@ -185,7 +186,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
 
     private fun initBookData() {
         booksFlowJob?.cancel()
-        booksFlowJob = launch {
+        booksFlowJob = lifecycleScope.launch {
             appDb.bookDao.flowByGroup(groupId).map { books ->
                 val booksDownload = books.filter {
                     !it.isAudio
@@ -208,7 +209,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
 
     @SuppressLint("NotifyDataSetChanged")
     private fun initGroupData() {
-        launch {
+        lifecycleScope.launch {
             appDb.bookGroupDao.flowAll().conflate().collect {
                 groupList.clear()
                 groupList.addAll(it)

+ 1 - 2
app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceDialog.kt

@@ -44,7 +44,6 @@ import io.legado.app.utils.viewbindingdelegate.viewBinding
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.conflate
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
 
 /**
@@ -205,7 +204,7 @@ class ChangeBookSourceDialog() : BaseDialogFragment(R.layout.dialog_book_change_
             }
         }
         lifecycleScope.launch {
-            appDb.bookSourceDao.flowEnabledGroups().flowOn(IO).conflate().collect {
+            appDb.bookSourceDao.flowEnabledGroups().conflate().collect {
                 groups.clear()
                 groups.addAll(it)
                 upGroupMenu()

+ 1 - 3
app/src/main/java/io/legado/app/ui/book/changesource/ChangeChapterSourceDialog.kt

@@ -45,10 +45,8 @@ import io.legado.app.utils.startActivity
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import io.legado.app.utils.visible
-import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.conflate
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
 
 
@@ -235,7 +233,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
             }
         }
         lifecycleScope.launch {
-            appDb.bookSourceDao.flowEnabledGroups().flowOn(IO).conflate().collect {
+            appDb.bookSourceDao.flowEnabledGroups().conflate().collect {
                 groups.clear()
                 groups.addAll(it)
                 upGroupMenu()

+ 14 - 13
app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt

@@ -5,9 +5,11 @@ import android.net.Uri
 import android.os.Bundle
 import android.view.Menu
 import android.view.MenuItem
+import androidx.activity.addCallback
 import androidx.activity.viewModels
 import androidx.appcompat.widget.PopupMenu
 import androidx.documentfile.provider.DocumentFile
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import io.legado.app.R
 import io.legado.app.constant.AppConst
@@ -23,9 +25,11 @@ import io.legado.app.ui.file.HandleFileContract
 import io.legado.app.ui.widget.SelectActionBar
 import io.legado.app.utils.*
 import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.Dispatchers.Main
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 import java.io.File
 
 /**
@@ -49,7 +53,12 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         searchView.queryHint = getString(R.string.screen) + " • " + getString(R.string.local_book)
-        launch {
+        onBackPressedDispatcher.addCallback(this) {
+            if (!goBackDir()) {
+                finish()
+            }
+        }
+        lifecycleScope.launch {
             initView()
             initEvent()
             if (setBookStorage() && AppConfig.importBookPath.isNullOrBlank()) {
@@ -129,7 +138,7 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
         viewModel.dataFlowStart = {
             initRootDoc()
         }
-        launch {
+        lifecycleScope.launch {
             viewModel.dataFlow.conflate().collect { docs ->
                 adapter.setItems(docs)
             }
@@ -235,9 +244,9 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
             val lastDoc = viewModel.subDocs.lastOrNull() ?: doc
             binding.refreshProgressBar.isAutoLoading = true
             scanDocJob?.cancel()
-            scanDocJob = launch(IO) {
-                viewModel.scanDoc(lastDoc, true, this) {
-                    launch {
+            scanDocJob = lifecycleScope.launch(IO) {
+                viewModel.scanDoc(lastDoc, true) {
+                    withContext(Main) {
                         binding.refreshProgressBar.isAutoLoading = false
                     }
                 }
@@ -281,14 +290,6 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
         viewModel.updateCallBackFlow(newText)
     }
 
-    @Deprecated("Deprecated in Java")
-    override fun onBackPressed() {
-        if (!goBackDir()) {
-            @Suppress("DEPRECATION")
-            super.onBackPressed()
-        }
-    }
-
     override fun upCountView() {
         binding.selectActionBar.upCountView(adapter.selectedUris.size, adapter.checkableCount)
     }

+ 16 - 11
app/src/main/java/io/legado/app/ui/book/import/local/ImportBookViewModel.kt

@@ -9,8 +9,11 @@ import io.legado.app.constant.AppPattern.archiveFileRegex
 import io.legado.app.constant.AppPattern.bookFileRegex
 import io.legado.app.constant.PreferKey
 import io.legado.app.model.localBook.LocalBook
-import io.legado.app.utils.*
-import kotlinx.coroutines.CoroutineScope
+import io.legado.app.utils.FileDoc
+import io.legado.app.utils.getPrefInt
+import io.legado.app.utils.isContentScheme
+import io.legado.app.utils.list
+import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.Main
 import kotlinx.coroutines.channels.awaitClose
@@ -20,7 +23,8 @@ import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.withContext
 import java.io.File
-import java.util.*
+import java.util.Collections
+import kotlin.coroutines.coroutineContext
 
 class ImportBookViewModel(application: Application) : BaseViewModel(application) {
     var rootDoc: FileDoc? = null
@@ -133,34 +137,35 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
         }
     }
 
-    fun scanDoc(
+    suspend fun scanDoc(
         fileDoc: FileDoc,
         isRoot: Boolean,
-        scope: CoroutineScope,
-        finally: (() -> Unit)? = null
+        finally: (suspend () -> Unit)? = null
     ) {
         if (isRoot) {
             dataCallback?.clear()
         }
-        if (!scope.isActive) {
+        if (!coroutineContext.isActive) {
             finally?.invoke()
             return
         }
         kotlin.runCatching {
             val list = ArrayList<FileDoc>()
             fileDoc.list()!!.forEach { docItem ->
-                if (!scope.isActive) {
+                if (!coroutineContext.isActive) {
                     finally?.invoke()
                     return
                 }
                 if (docItem.isDir) {
-                    scanDoc(docItem, false, scope)
-                } else if (docItem.name.matches(bookFileRegex) || docItem.name.matches(archiveFileRegex)
+                    scanDoc(docItem, false)
+                } else if (docItem.name.matches(bookFileRegex) || docItem.name.matches(
+                        archiveFileRegex
+                    )
                 ) {
                     list.add(docItem)
                 }
             }
-            if (!scope.isActive) {
+            if (!coroutineContext.isActive) {
                 finally?.invoke()
                 return
             }

+ 8 - 9
app/src/main/java/io/legado/app/ui/book/import/remote/RemoteBookActivity.kt

@@ -6,8 +6,10 @@ import android.os.Bundle
 import android.view.Menu
 import android.view.MenuItem
 import android.view.SubMenu
+import androidx.activity.addCallback
 import androidx.activity.viewModels
 import androidx.core.view.isGone
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import io.legado.app.R
 import io.legado.app.data.appDb
@@ -43,7 +45,12 @@ class RemoteBookActivity : BaseImportBookActivity<RemoteBookViewModel>(),
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         searchView.queryHint = getString(R.string.screen) + " • " + getString(R.string.remote_book)
-        launch {
+        onBackPressedDispatcher.addCallback(this) {
+            if (!goBackDir()) {
+                finish()
+            }
+        }
+        lifecycleScope.launch {
             if (!setBookStorage()) {
                 finish()
                 return@launch
@@ -152,14 +159,6 @@ class RemoteBookActivity : BaseImportBookActivity<RemoteBookViewModel>(),
         }
     }
 
-    @Deprecated("Deprecated in Java")
-    override fun onBackPressed() {
-        if (!goBackDir()) {
-            @Suppress("DEPRECATION")
-            super.onBackPressed()
-        }
-    }
-
     private fun goBackDir(): Boolean {
         if (viewModel.dirList.isEmpty()) {
             return false

+ 7 - 5
app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt

@@ -10,6 +10,7 @@ import android.widget.CheckBox
 import android.widget.LinearLayout
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.constant.Theme
@@ -62,7 +63,7 @@ class BookInfoActivity :
     private val tocActivityResult = registerForActivityResult(TocActivityResult()) {
         it?.let {
             viewModel.getBook(false)?.let { book ->
-                launch {
+                lifecycleScope.launch {
                     withContext(IO) {
                         book.durChapterIndex = it.first
                         book.durChapterPos = it.second
@@ -247,7 +248,7 @@ class BookInfoActivity :
         book: Book,
         bookWebDav: RemoteBookWebDav? = AppWebDav.defaultBookWebDav
     ) {
-        launch {
+        lifecycleScope.launch {
             waitDialog.setText("上传中.....")
             waitDialog.show()
             try {
@@ -431,13 +432,14 @@ class BookInfoActivity :
     }
 
     private fun setSourceVariable() {
-        launch {
+        lifecycleScope.launch {
             val source = viewModel.bookSource
             if (source == null) {
                 toastOnUi("书源不存在")
                 return@launch
             }
-            val comment = source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取")
+            val comment =
+                source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取")
             val variable = withContext(IO) { source.getVariable() }
             showDialogFragment(
                 VariableDialog(
@@ -451,7 +453,7 @@ class BookInfoActivity :
     }
 
     private fun setBookVariable() {
-        launch {
+        lifecycleScope.launch {
             val source = viewModel.bookSource
             if (source == null) {
                 toastOnUi("书源不存在")

+ 4 - 3
app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageActivity.kt

@@ -11,6 +11,7 @@ import android.widget.LinearLayout
 import androidx.activity.viewModels
 import androidx.appcompat.widget.PopupMenu
 import androidx.appcompat.widget.SearchView
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.LinearLayoutManager
 import io.legado.app.R
@@ -72,7 +73,7 @@ class BookshelfManageActivity :
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         viewModel.groupId = intent.getLongExtra("groupId", -1)
-        launch {
+        lifecycleScope.launch {
             viewModel.groupName = withContext(IO) {
                 appDb.bookGroupDao.getByID(viewModel.groupId)?.groupName
                     ?: getString(R.string.no_group)
@@ -184,7 +185,7 @@ class BookshelfManageActivity :
 
     @SuppressLint("NotifyDataSetChanged")
     private fun initGroupData() {
-        launch {
+        lifecycleScope.launch {
             appDb.bookGroupDao.flowAll().conflate().collect {
                 groupList.clear()
                 groupList.addAll(it)
@@ -196,7 +197,7 @@ class BookshelfManageActivity :
 
     private fun upBookDataByGroupId() {
         booksFlowJob?.cancel()
-        booksFlowJob = launch {
+        booksFlowJob = lifecycleScope.launch {
             val bookSort = AppConfig.getBookSortByGroupId(viewModel.groupId)
             appDb.bookDao.flowByGroup(viewModel.groupId).map { list ->
                 when (bookSort) {

+ 12 - 11
app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt

@@ -13,6 +13,7 @@ import androidx.appcompat.widget.PopupMenu
 import androidx.core.view.get
 import androidx.core.view.isVisible
 import androidx.core.view.size
+import androidx.lifecycle.lifecycleScope
 import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
 import io.legado.app.BuildConfig
 import io.legado.app.R
@@ -323,7 +324,7 @@ class ReadBookActivity : BaseReadBookActivity(),
                     }
                 }
             }
-            launch {
+            lifecycleScope.launch {
                 menu.findItem(R.id.menu_get_progress)?.isVisible = withContext(IO) {
                     AppWebDav.isOk
                 }
@@ -344,7 +345,7 @@ class ReadBookActivity : BaseReadBookActivity(),
                 }
             }
 
-            R.id.menu_chapter_change_source -> launch {
+            R.id.menu_chapter_change_source -> lifecycleScope.launch {
                 val book = ReadBook.book ?: return@launch
                 val chapter =
                     appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
@@ -769,7 +770,7 @@ class ReadBookActivity : BaseReadBookActivity(),
     }
 
     override fun upMenuView() {
-        launch {
+        lifecycleScope.launch {
             upMenu()
             binding.readMenu.upBookView()
         }
@@ -799,7 +800,7 @@ class ReadBookActivity : BaseReadBookActivity(),
         resetPageOffset: Boolean,
         success: (() -> Unit)?
     ) {
-        launch {
+        lifecycleScope.launch {
             autoPageProgress = 0
             binding.readView.upContent(relativePosition, resetPageOffset)
             upSeekBarProgress()
@@ -809,7 +810,7 @@ class ReadBookActivity : BaseReadBookActivity(),
     }
 
     override fun upPageAnim() {
-        launch {
+        lifecycleScope.launch {
             binding.readView.upPageAnim()
         }
     }
@@ -822,7 +823,7 @@ class ReadBookActivity : BaseReadBookActivity(),
      * 页面改变
      */
     override fun pageChanged() {
-        launch {
+        lifecycleScope.launch {
             autoPageProgress = 0
             upSeekBarProgress()
             startBackupJob()
@@ -855,7 +856,7 @@ class ReadBookActivity : BaseReadBookActivity(),
             viewModel.changeTo(book, toc)
         } else {
             ReadAloud.stop(this)
-            launch {
+            lifecycleScope.launch {
                 withContext(IO) {
                     ReadBook.book?.migrateTo(book, toc)
                     book.removeType(BookType.updateError)
@@ -925,7 +926,7 @@ class ReadBookActivity : BaseReadBookActivity(),
 
     private fun autoPagePlus() {
         autoPageJob?.cancel()
-        autoPageJob = launch {
+        autoPageJob = lifecycleScope.launch {
             while (isActive) {
                 var delayMillis = ReadBookConfig.autoReadSpeed * 1000L / binding.readView.height
                 var scrollOffset = 1
@@ -1307,7 +1308,7 @@ class ReadBookActivity : BaseReadBookActivity(),
 
     private fun startBackupJob() {
         backupJob?.cancel()
-        backupJob = launch(IO) {
+        backupJob = lifecycleScope.launch(IO) {
             delay(300000)
             ReadBook.book?.let {
                 AppWebDav.uploadBookProgress(it)
@@ -1389,7 +1390,7 @@ class ReadBookActivity : BaseReadBookActivity(),
             }
         }
         observeEventSticky<Int>(EventBus.TTS_PROGRESS) { chapterStart ->
-            launch(IO) {
+            lifecycleScope.launch(IO) {
                 if (BaseReadAloudService.isPlay()) {
                     ReadBook.curTextChapter?.let { textChapter ->
                         val pageIndex = ReadBook.durPageIndex
@@ -1432,7 +1433,7 @@ class ReadBookActivity : BaseReadBookActivity(),
      */
     override fun screenOffTimerStart() {
         keepScreenJon?.cancel()
-        keepScreenJon = launch {
+        keepScreenJon = lifecycleScope.launch {
             if (screenTimeOut < 0) {
                 keepScreenOn(true)
                 return@launch

+ 21 - 8
app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt

@@ -11,6 +11,7 @@ import android.widget.TextView
 import androidx.activity.viewModels
 import androidx.appcompat.widget.SearchView
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.google.android.flexbox.FlexboxLayoutManager
@@ -22,16 +23,28 @@ import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.SearchKeyword
 import io.legado.app.databinding.ActivityBookSearchBinding
 import io.legado.app.lib.dialogs.alert
-import io.legado.app.lib.theme.*
+import io.legado.app.lib.theme.Selector
+import io.legado.app.lib.theme.accentColor
+import io.legado.app.lib.theme.backgroundColor
+import io.legado.app.lib.theme.primaryColor
+import io.legado.app.lib.theme.primaryTextColor
 import io.legado.app.ui.about.AppLogDialog
 import io.legado.app.ui.book.info.BookInfoActivity
 import io.legado.app.ui.book.source.manage.BookSourceActivity
-import io.legado.app.utils.*
+import io.legado.app.utils.ColorUtils
+import io.legado.app.utils.applyTint
+import io.legado.app.utils.getPrefBoolean
+import io.legado.app.utils.gone
+import io.legado.app.utils.invisible
+import io.legado.app.utils.putPrefBoolean
+import io.legado.app.utils.setEdgeEffectColor
+import io.legado.app.utils.showDialogFragment
+import io.legado.app.utils.startActivity
 import io.legado.app.utils.viewbindingdelegate.viewBinding
+import io.legado.app.utils.visible
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.conflate
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import splitties.init.appCtx
@@ -67,7 +80,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
     private var isManualStopSearch = false
     private val searchFinishCallback: (isEmpty: Boolean) -> Unit = searchFinish@{ isEmpty ->
         if (!isEmpty || viewModel.searchScope.isAll()) return@searchFinish
-        launch {
+        lifecycleScope.launch {
             alert("搜索结果为空") {
                 val precisionSearch = appCtx.getPrefBoolean(PreferKey.precisionSearch)
                 if (precisionSearch) {
@@ -280,7 +293,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
         viewModel.searchBookLiveData.observe(this) {
             adapter.setItems(it)
         }
-        launch(IO) {
+        lifecycleScope.launch(IO) {
             appDb.bookSourceDao.flowEnabledGroups().collect {
                 groups = it
             }
@@ -337,7 +350,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
      */
     private fun upHistory(key: String? = null) {
         booksFlowJob?.cancel()
-        booksFlowJob = launch {
+        booksFlowJob = lifecycleScope.launch {
             if (key.isNullOrBlank()) {
                 binding.tvBookShow.gone()
                 binding.rvBookshelfSearch.gone()
@@ -355,7 +368,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
             }
         }
         historyFlowJob?.cancel()
-        historyFlowJob = launch {
+        historyFlowJob = lifecycleScope.launch {
             when {
                 key.isNullOrBlank() -> appDb.searchKeywordDao.flowByTime()
                 else -> appDb.searchKeywordDao.flowSearch(key)
@@ -425,7 +438,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
      * 点击历史关键字
      */
     override fun searchHistory(key: String) {
-        launch {
+        lifecycleScope.launch {
             when {
                 searchView.query.toString() == key -> {
                     searchView.setQuery(key, true)

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt

@@ -10,6 +10,7 @@ import android.widget.EditText
 import androidx.activity.viewModels
 import androidx.appcompat.widget.SearchView
 import androidx.core.view.allViews
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.constant.AppLog
@@ -172,7 +173,7 @@ class SearchContentActivity :
     }
 
     private fun initCacheFileNames(book: Book) {
-        initJob = async {
+        initJob = lifecycleScope.async {
             withContext(IO) {
                 viewModel.cacheChapterNames.addAll(BookHelp.getChapterFiles(book))
             }
@@ -202,7 +203,7 @@ class SearchContentActivity :
         viewModel.lastQuery = query
         binding.refreshProgressBar.isAutoLoading = true
         binding.fbStop.visible()
-        searchJob = launch(IO) {
+        searchJob = lifecycleScope.launch(IO) {
             initJob?.await()
             kotlin.runCatching {
                 appDb.bookChapterDao.getChapterList(viewModel.bookUrl).forEach { bookChapter ->

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugActivity.kt

@@ -7,6 +7,7 @@ import android.view.MenuItem
 import android.view.View
 import androidx.activity.viewModels
 import androidx.appcompat.widget.SearchView
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.databinding.ActivitySourceDebugBinding
@@ -47,7 +48,7 @@ class BookSourceDebugActivity : VMBaseActivity<ActivitySourceDebugBinding, BookS
             initHelpView()
         }
         viewModel.observe { state, msg ->
-            launch {
+            lifecycleScope.launch {
                 adapter.addItem(msg)
                 if (state == -1 || state == 1000) {
                     binding.rotateLoading.gone()
@@ -113,7 +114,7 @@ class BookSourceDebugActivity : VMBaseActivity<ActivitySourceDebugBinding, BookS
         binding.textContent.onClick {
             prefixAutoComplete("--")
         }
-        launch {
+        lifecycleScope.launch {
             val exploreKinds = viewModel.bookSource?.exploreKinds()?.filter {
                 !it.url.isNullOrBlank()
             }

+ 4 - 3
app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt

@@ -6,6 +6,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.widget.EditText
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import com.google.android.material.tabs.TabLayout
 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
@@ -86,7 +87,7 @@ class BookSourceEditActivity :
     }
 
     private val softKeyboardTool by lazy {
-        KeyboardToolPop(this, this, binding.root, this)
+        KeyboardToolPop(this, lifecycleScope, binding.root, this)
     }
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
@@ -556,7 +557,7 @@ class BookSourceEditActivity :
     }
 
     private fun alertGroups() {
-        launch {
+        lifecycleScope.launch {
             val groups = withContext(IO) {
                 appDb.bookSourceDao.allGroups()
             }
@@ -628,7 +629,7 @@ class BookSourceEditActivity :
 
     private fun setSourceVariable() {
         viewModel.save(getSource()) { source ->
-            launch {
+            lifecycleScope.launch {
                 val comment =
                     source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取")
                 val variable = withContext(IO) { source.getVariable() }

+ 5 - 4
app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt

@@ -9,6 +9,7 @@ import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.widget.PopupMenu
 import androidx.appcompat.widget.SearchView
 import androidx.core.os.bundleOf
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import com.google.android.material.snackbar.Snackbar
 import io.legado.app.R
@@ -249,7 +250,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
     private fun upBookSource(searchKey: String? = null) {
         this.searchKey = searchKey
         sourceFlowJob?.cancel()
-        sourceFlowJob = launch {
+        sourceFlowJob = lifecycleScope.launch {
             when {
                 searchKey.isNullOrEmpty() -> {
                     appDb.bookSourceDao.flowAll()
@@ -337,8 +338,8 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
     }
 
     private fun initLiveDataGroup() {
-        launch {
-            appDb.bookSourceDao.flowGroups().flowOn(IO).conflate().collect {
+        lifecycleScope.launch {
+            appDb.bookSourceDao.flowGroups().conflate().collect {
                 groups.clear()
                 groups.addAll(it)
                 upGroupMenu()
@@ -563,7 +564,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
     }
 
     private fun checkMessageRefreshJob(firstItem: Int, lastItem: Int): Job {
-        return async(start = CoroutineStart.LAZY) {
+        return lifecycleScope.async(start = CoroutineStart.LAZY) {
             flow {
                 while (true) {
                     emit(Debug.isChecking)

+ 1 - 3
app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt

@@ -26,8 +26,6 @@ import io.legado.app.utils.applyTint
 import io.legado.app.utils.requestInputMethod
 import io.legado.app.utils.setLayout
 import io.legado.app.utils.viewbindingdelegate.viewBinding
-import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
 
 
@@ -58,7 +56,7 @@ class GroupManageDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
 
     private fun initData() {
         lifecycleScope.launch {
-            appDb.bookSourceDao.flowGroups().flowOn(IO).collect {
+            appDb.bookSourceDao.flowGroups().collect {
                 adapter.setItems(it)
             }
         }

+ 2 - 1
app/src/main/java/io/legado/app/ui/book/toc/rule/TxtTocRuleActivity.kt

@@ -6,6 +6,7 @@ import android.view.Menu
 import android.view.MenuItem
 import androidx.activity.viewModels
 import androidx.appcompat.widget.PopupMenu
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
@@ -101,7 +102,7 @@ class TxtTocRuleActivity : VMBaseActivity<ActivityTxtTocRuleBinding, TxtTocRuleV
     }
 
     private fun initData() {
-        launch {
+        lifecycleScope.launch {
             appDb.txtTocRuleDao.observeAll().conflate().collect { tocRules ->
                 adapter.setItems(tocRules, adapter.diffItemCallBack)
                 upCountView()

+ 2 - 1
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleActivity.kt

@@ -6,6 +6,7 @@ import android.view.Menu
 import android.view.MenuItem
 import androidx.activity.viewModels
 import androidx.appcompat.widget.PopupMenu
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.LinearLayoutManager
 import io.legado.app.R
@@ -110,7 +111,7 @@ class DictRuleActivity : VMBaseActivity<ActivityDictRuleBinding, DictRuleViewMod
     }
 
     private fun observeDictRuleData() {
-        launch {
+        lifecycleScope.launch {
             appDb.dictRuleDao.flowAll().collect {
                 adapter.setItems(it, adapter.diffItemCallBack)
             }

+ 3 - 2
app/src/main/java/io/legado/app/ui/main/MainActivity.kt

@@ -14,6 +14,7 @@ import androidx.core.view.postDelayed
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
 import androidx.fragment.app.FragmentStatePagerAdapter
+import androidx.lifecycle.lifecycleScope
 import androidx.viewpager.widget.ViewPager
 import com.google.android.material.bottomnavigation.BottomNavigationView
 import io.legado.app.BuildConfig
@@ -126,7 +127,7 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
 
     override fun onPostCreate(savedInstanceState: Bundle?) {
         super.onPostCreate(savedInstanceState)
-        launch {
+        lifecycleScope.launch {
             //隐私协议
             if (!privacyPolicy()) return@launch
             //版本更新
@@ -269,7 +270,7 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
      * 备份同步
      */
     private fun backupSync() {
-        launch {
+        lifecycleScope.launch {
             val lastBackupFile =
                 withContext(IO) { AppWebDav.lastBackUp().getOrNull() } ?: return@launch
             if (lastBackupFile.lastModify - LocalConfig.lastBackup > DateUtils.MINUTE_IN_MILLIS) {

+ 1 - 1
app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt

@@ -130,7 +130,7 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
 
     private fun initGroupData() {
         lifecycleScope.launch {
-            appDb.bookSourceDao.flowExploreGroups().flowOn(IO).conflate().collect {
+            appDb.bookSourceDao.flowExploreGroups().conflate().collect {
                 groups.clear()
                 groups.addAll(it)
                 upGroupsMenu()

+ 5 - 2
app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt

@@ -12,6 +12,7 @@ import androidx.activity.result.contract.ActivityResultContracts
 import androidx.activity.viewModels
 import androidx.appcompat.widget.PopupMenu
 import androidx.appcompat.widget.SearchView
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.LinearLayoutManager
 import io.legado.app.R
@@ -189,14 +190,16 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
     private fun observeReplaceRuleData(searchKey: String? = null) {
         dataInit = false
         replaceRuleFlowJob?.cancel()
-        replaceRuleFlowJob = launch {
+        replaceRuleFlowJob = lifecycleScope.launch {
             when {
                 searchKey.isNullOrEmpty() -> {
                     appDb.replaceRuleDao.flowAll()
                 }
+
                 searchKey == getString(R.string.no_group) -> {
                     appDb.replaceRuleDao.flowNoGroup()
                 }
+
                 searchKey.startsWith("group:") -> {
                     val key = searchKey.substringAfter("group:")
                     appDb.replaceRuleDao.flowGroupSearch("%$key%")
@@ -218,7 +221,7 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
     }
 
     private fun observeGroupData() {
-        launch {
+        lifecycleScope.launch {
             appDb.replaceRuleDao.flowGroups().collect {
                 groups.clear()
                 groups.addAll(it)

+ 2 - 1
app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt

@@ -7,6 +7,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.widget.EditText
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.data.entities.ReplaceRule
@@ -49,7 +50,7 @@ class ReplaceEditActivity :
     override val viewModel by viewModels<ReplaceEditViewModel>()
 
     private val softKeyboardTool by lazy {
-        KeyboardToolPop(this, this, binding.root, this)
+        KeyboardToolPop(this, lifecycleScope, binding.root, this)
     }
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {

+ 5 - 3
app/src/main/java/io/legado/app/ui/rss/article/RssSortActivity.kt

@@ -9,6 +9,7 @@ import android.view.ViewGroup
 import androidx.activity.viewModels
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentStatePagerAdapter
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.databinding.ActivityRssArtivlesBinding
@@ -91,7 +92,7 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
     }
 
     private fun upFragments() {
-        launch {
+        lifecycleScope.launch {
             viewModel.rssSource?.sortUrls()?.let {
                 sortList.clear()
                 sortList.addAll(it)
@@ -106,13 +107,14 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
     }
 
     private fun setSourceVariable() {
-        launch {
+        lifecycleScope.launch {
             val source = viewModel.rssSource
             if (source == null) {
                 toastOnUi("源不存在")
                 return@launch
             }
-            val comment = source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取")
+            val comment =
+                source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取")
             val variable = withContext(Dispatchers.IO) { source.getVariable() }
             showDialogFragment(
                 VariableDialog(

+ 2 - 1
app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesActivity.kt

@@ -1,6 +1,7 @@
 package io.legado.app.ui.rss.favorites
 
 import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import io.legado.app.base.BaseActivity
 import io.legado.app.data.appDb
@@ -36,7 +37,7 @@ class RssFavoritesActivity : BaseActivity<ActivityRssFavoritesBinding>(),
     }
 
     private fun initData() {
-        launch {
+        lifecycleScope.launch {
             appDb.rssStarDao.liveAll().conflate().collect {
                 adapter.setItems(it)
             }

+ 2 - 1
app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt

@@ -11,6 +11,7 @@ import android.webkit.*
 import androidx.activity.addCallback
 import androidx.activity.viewModels
 import androidx.core.view.size
+import androidx.lifecycle.lifecycleScope
 import com.script.rhino.RhinoScriptEngine
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
@@ -263,7 +264,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
     }
 
     private fun upTtsMenu(isPlaying: Boolean) {
-        launch {
+        lifecycleScope.launch {
             if (isPlaying) {
                 ttsMenuItem?.setIcon(R.drawable.ic_stop_black_24dp)
                 ttsMenuItem?.setTitle(R.string.aloud_stop)

+ 2 - 1
app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt

@@ -5,6 +5,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.widget.SearchView
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.databinding.ActivitySourceDebugBinding
@@ -30,7 +31,7 @@ class RssSourceDebugActivity : VMBaseActivity<ActivitySourceDebugBinding, RssSou
         initRecyclerView()
         initSearchView()
         viewModel.observe { state, msg ->
-            launch {
+            lifecycleScope.launch {
                 adapter.addItem(msg)
                 if (state == -1 || state == 1000) {
                     binding.rotateLoading.gone()

+ 3 - 2
app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt

@@ -6,6 +6,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.widget.EditText
 import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
 import com.google.android.material.tabs.TabLayout
 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
 import io.legado.app.R
@@ -50,7 +51,7 @@ class RssSourceEditActivity :
     override val binding by viewBinding(ActivityRssSourceEditBinding::inflate)
     override val viewModel by viewModels<RssSourceEditViewModel>()
     private val softKeyboardTool by lazy {
-        KeyboardToolPop(this, this, binding.root, this)
+        KeyboardToolPop(this, lifecycleScope, binding.root, this)
     }
     private val adapter by lazy { RssSourceEditAdapter() }
     private val sourceEntities: ArrayList<EditEntity> = ArrayList()
@@ -328,7 +329,7 @@ class RssSourceEditActivity :
 
     private fun setSourceVariable() {
         viewModel.save(getRssSource()) { source ->
-            launch {
+            lifecycleScope.launch {
                 val comment =
                     source.getDisplayVariableComment("源变量可在js中通过source.getVariable()获取")
                 val variable = withContext(Dispatchers.IO) { source.getVariable() }

+ 5 - 2
app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt

@@ -10,6 +10,7 @@ import android.widget.EditText
 import androidx.activity.viewModels
 import androidx.appcompat.widget.PopupMenu
 import androidx.appcompat.widget.SearchView
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
@@ -219,7 +220,7 @@ class RssSourceActivity : VMBaseActivity<ActivityRssSourceBinding, RssSourceView
     }
 
     private fun initGroupFlow() {
-        launch {
+        lifecycleScope.launch {
             appDb.rssSourceDao.flowGroups().conflate().collect {
                 groups.clear()
                 groups.addAll(it)
@@ -302,14 +303,16 @@ class RssSourceActivity : VMBaseActivity<ActivityRssSourceBinding, RssSourceView
 
     private fun upSourceFlow(searchKey: String? = null) {
         sourceFlowJob?.cancel()
-        sourceFlowJob = launch {
+        sourceFlowJob = lifecycleScope.launch {
             when {
                 searchKey.isNullOrBlank() -> {
                     appDb.rssSourceDao.flowAll()
                 }
+
                 searchKey == getString(R.string.enabled) -> {
                     appDb.rssSourceDao.flowEnabled()
                 }
+
                 searchKey == getString(R.string.disabled) -> {
                     appDb.rssSourceDao.flowDisabled()
                 }

+ 6 - 5
app/src/main/java/io/legado/app/ui/rss/subscription/RuleSubActivity.kt

@@ -4,6 +4,7 @@ import android.os.Bundle
 import android.view.Menu
 import android.view.MenuItem
 import androidx.core.view.isGone
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import io.legado.app.R
 import io.legado.app.base.BaseActivity
@@ -61,7 +62,7 @@ class RuleSubActivity : BaseActivity<ActivityRuleSubBinding>(),
     }
 
     private fun initData() {
-        launch {
+        lifecycleScope.launch {
             appDb.ruleSubDao.flowAll().conflate().collect {
                 binding.tvEmptyMsg.isGone = it.isNotEmpty()
                 adapter.setItems(it)
@@ -92,7 +93,7 @@ class RuleSubActivity : BaseActivity<ActivityRuleSubBinding>(),
             }
             customView { alertBinding.root }
             okButton {
-                launch {
+                lifecycleScope.launch {
                     ruleSub.type = alertBinding.spType.selectedItemPosition
                     ruleSub.name = alertBinding.etName.text?.toString() ?: ""
                     ruleSub.url = alertBinding.etUrl.text?.toString() ?: ""
@@ -113,19 +114,19 @@ class RuleSubActivity : BaseActivity<ActivityRuleSubBinding>(),
     }
 
     override fun delSubscription(ruleSub: RuleSub) {
-        launch(IO) {
+        lifecycleScope.launch(IO) {
             appDb.ruleSubDao.delete(ruleSub)
         }
     }
 
     override fun updateSourceSub(vararg ruleSub: RuleSub) {
-        launch(IO) {
+        lifecycleScope.launch(IO) {
             appDb.ruleSubDao.update(*ruleSub)
         }
     }
 
     override fun upOrder() {
-        launch(IO) {
+        lifecycleScope.launch(IO) {
             val sourceSubs = appDb.ruleSubDao.all
             for ((index: Int, ruleSub: RuleSub) in sourceSubs.withIndex()) {
                 ruleSub.customOrder = index + 1