Răsfoiți Sursa

Lessen the use of GlobalScope `launchIO` (#7916)

* Lessen the use of GlobalScope `launchIO`

* Wrap some calls with `NonCancellable` context
AntsyLich 2 ani în urmă
părinte
comite
da95ecb686

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt

@@ -244,7 +244,7 @@ open class BrowseSourcePresenter(
             if (!new.favorite) {
                 new = new.removeCovers(coverCache)
             } else {
-                ChapterSettingsHelper.applySettingDefaults(manga)
+                ChapterSettingsHelper.applySettingDefaults(manga.id)
 
                 autoAddTrack(manga)
             }

+ 5 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt

@@ -49,6 +49,7 @@ import eu.kanade.tachiyomi.ui.library.setting.display
 import eu.kanade.tachiyomi.ui.library.setting.sort
 import eu.kanade.tachiyomi.util.lang.combineLatest
 import eu.kanade.tachiyomi.util.lang.launchIO
+import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
 import eu.kanade.tachiyomi.util.removeCovers
 import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
 import kotlinx.coroutines.Job
@@ -511,7 +512,7 @@ class LibraryPresenter(
      * @param mangas the list of manga.
      */
     fun downloadUnreadChapters(mangas: List<Manga>) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             mangas.forEach { manga ->
                 val chapters = getChapterByMangaId.await(manga.id)
                     .filter { !it.read }
@@ -528,7 +529,7 @@ class LibraryPresenter(
      * @param mangas the list of manga.
      */
     fun markReadStatus(mangas: List<Manga>, read: Boolean) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             mangas.forEach { manga ->
                 setReadStatus.await(
                     manga = manga,
@@ -546,7 +547,7 @@ class LibraryPresenter(
      * @param deleteChapters whether to delete downloaded chapters.
      */
     fun removeMangas(mangaList: List<DbManga>, deleteFromLibrary: Boolean, deleteChapters: Boolean) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             val mangaToDelete = mangaList.distinctBy { it.id }
 
             if (deleteFromLibrary) {
@@ -579,7 +580,7 @@ class LibraryPresenter(
      * @param removeCategories the categories to remove in all mangas.
      */
     fun setMangaCategories(mangaList: List<Manga>, addCategories: List<Long>, removeCategories: List<Long>) {
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             mangaList.map { manga ->
                 val categoryIds = getCategories.await(manga.id)
                     .map { it.id }

+ 14 - 15
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt

@@ -42,6 +42,7 @@ import eu.kanade.tachiyomi.ui.manga.track.TrackItem
 import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
 import eu.kanade.tachiyomi.util.chapter.getChapterSort
 import eu.kanade.tachiyomi.util.lang.launchIO
+import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
 import eu.kanade.tachiyomi.util.lang.toRelativeString
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.preference.asHotFlow
@@ -396,7 +397,6 @@ class MangaPresenter(
     /**
      * Move the given manga to categories.
      *
-     * @param manga the manga to move.
      * @param categories the selected categories.
      */
     private fun moveMangaToCategories(categories: List<Category>) {
@@ -413,7 +413,6 @@ class MangaPresenter(
     /**
      * Move the given manga to the category.
      *
-     * @param manga the manga to move.
      * @param category the selected category, or null for default category.
      */
     private fun moveMangaToCategory(category: Category?) {
@@ -643,7 +642,7 @@ class MangaPresenter(
      * @param chapters the list of chapters to delete.
      */
     fun deleteChapters(chapters: List<DomainChapter>) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             val chapters2 = chapters.map { it.toDbChapter() }
             try {
                 updateSuccessState { successState ->
@@ -675,10 +674,10 @@ class MangaPresenter(
     }
 
     private fun downloadNewChapters(chapters: List<DomainChapter>) {
-        presenterScope.launchIO {
-            val manga = successState?.manga ?: return@launchIO
+        presenterScope.launchNonCancellableIO {
+            val manga = successState?.manga ?: return@launchNonCancellableIO
             val categories = getCategories.await(manga.id).map { it.id }
-            if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(categories, preferences)) return@launchIO
+            if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(categories, preferences)) return@launchNonCancellableIO
             downloadChapters(chapters)
         }
     }
@@ -695,7 +694,7 @@ class MangaPresenter(
             State.INCLUDE -> DomainManga.CHAPTER_SHOW_UNREAD
             State.EXCLUDE -> DomainManga.CHAPTER_SHOW_READ
         }
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             setMangaChapterFlags.awaitSetUnreadFilter(manga, flag)
         }
     }
@@ -713,7 +712,7 @@ class MangaPresenter(
             State.EXCLUDE -> DomainManga.CHAPTER_SHOW_NOT_DOWNLOADED
         }
 
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             setMangaChapterFlags.awaitSetDownloadedFilter(manga, flag)
         }
     }
@@ -731,7 +730,7 @@ class MangaPresenter(
             State.EXCLUDE -> DomainManga.CHAPTER_SHOW_NOT_BOOKMARKED
         }
 
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             setMangaChapterFlags.awaitSetBookmarkFilter(manga, flag)
         }
     }
@@ -743,7 +742,7 @@ class MangaPresenter(
     fun setDisplayMode(mode: Long) {
         val manga = successState?.manga ?: return
 
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             setMangaChapterFlags.awaitSetDisplayMode(manga, mode)
         }
     }
@@ -755,7 +754,7 @@ class MangaPresenter(
     fun setSorting(sort: Long) {
         val manga = successState?.manga ?: return
 
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             setMangaChapterFlags.awaitSetSortingModeOrFlipOrder(manga, sort)
         }
     }
@@ -870,7 +869,7 @@ class MangaPresenter(
 
     fun refreshTrackers() {
         refreshTrackersJob?.cancel()
-        refreshTrackersJob = launchIO {
+        refreshTrackersJob = presenterScope.launchNonCancellableIO {
             supervisorScope {
                 try {
                     trackList
@@ -918,7 +917,7 @@ class MangaPresenter(
         val successState = successState ?: return
         if (item != null) {
             item.manga_id = successState.manga.id
-            launchIO {
+            presenterScope.launchNonCancellableIO {
                 try {
                     val allChapters = successState.chapters.map { it.chapter }
                     val hasReadChapters = allChapters.any { it.read }
@@ -959,13 +958,13 @@ class MangaPresenter(
     fun unregisterTracking(service: TrackService) {
         val manga = successState?.manga ?: return
 
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             deleteTrack.await(manga.id, service.id)
         }
     }
 
     private fun updateRemote(track: Track, service: TrackService) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             try {
                 service.update(track)
 

+ 10 - 9
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt

@@ -47,6 +47,7 @@ import eu.kanade.tachiyomi.util.chapter.getChapterSort
 import eu.kanade.tachiyomi.util.editCover
 import eu.kanade.tachiyomi.util.lang.byteSize
 import eu.kanade.tachiyomi.util.lang.launchIO
+import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
 import eu.kanade.tachiyomi.util.lang.takeBytes
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.storage.DiskUtil
@@ -231,7 +232,7 @@ class ReaderPresenter(
      */
     fun onSaveInstanceStateNonConfigurationChange() {
         val currentChapter = getCurrentChapter() ?: return
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             saveChapterProgress(currentChapter)
         }
     }
@@ -518,7 +519,7 @@ class ReaderPresenter(
      * Called when reader chapter is changed in reader or when activity is paused.
      */
     private fun saveReadingProgress(readerChapter: ReaderChapter) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             saveChapterProgress(readerChapter)
             saveChapterHistory(readerChapter)
         }
@@ -599,7 +600,7 @@ class ReaderPresenter(
     fun bookmarkCurrentChapter(bookmarked: Boolean) {
         val chapter = getCurrentChapter()?.chapter ?: return
         chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             updateChapter.await(
                 ChapterUpdate(
                     id = chapter.id!!.toLong(),
@@ -712,7 +713,7 @@ class ReaderPresenter(
 
         // Copy file in background.
         try {
-            presenterScope.launchIO {
+            presenterScope.launchNonCancellableIO {
                 val uri = imageSaver.save(
                     image = Image.Page(
                         inputStream = page.stream!!,
@@ -748,7 +749,7 @@ class ReaderPresenter(
         val filename = generateFilename(manga, page)
 
         try {
-            presenterScope.launchIO {
+            presenterScope.launchNonCancellableIO {
                 destDir.deleteRecursively()
                 val uri = imageSaver.save(
                     image = Image.Page(
@@ -774,7 +775,7 @@ class ReaderPresenter(
         val manga = manga?.toDomainManga() ?: return
         val stream = page.stream ?: return
 
-        presenterScope.launchIO {
+        presenterScope.launchNonCancellableIO {
             try {
                 manga.editCover(context, stream())
                 withUIContext {
@@ -820,7 +821,7 @@ class ReaderPresenter(
         val trackManager = Injekt.get<TrackManager>()
         val context = Injekt.get<Application>()
 
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             getTracks.await(manga.id!!)
                 .mapNotNull { track ->
                     val service = trackManager.getService(track.syncId)
@@ -858,7 +859,7 @@ class ReaderPresenter(
         if (!chapter.chapter.read) return
         val manga = manga ?: return
 
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             downloadManager.enqueueDeleteChapters(listOf(chapter.chapter), manga.toDomainManga()!!)
         }
     }
@@ -868,7 +869,7 @@ class ReaderPresenter(
      * are ignored.
      */
     private fun deletePendingChapters() {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             downloadManager.deletePendingChapters()
         }
     }

+ 4 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt

@@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 import eu.kanade.tachiyomi.util.lang.launchIO
+import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
 import eu.kanade.tachiyomi.util.lang.toDateKey
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.system.logcat
@@ -221,7 +222,7 @@ class UpdatesPresenter(
      * @param updatesItem the list of chapters to download.
      */
     fun downloadChapters(updatesItem: List<UpdatesItem>) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values
             for (updates in groupedUpdates) {
                 val mangaId = updates.first().update.mangaId
@@ -240,7 +241,7 @@ class UpdatesPresenter(
      * @param updatesItem list of chapters
      */
     fun deleteChapters(updatesItem: List<UpdatesItem>) {
-        launchIO {
+        presenterScope.launchNonCancellableIO {
             val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values
             val deletedIds = groupedUpdates.flatMap { updates ->
                 val mangaId = updates.first().update.mangaId
@@ -253,7 +254,7 @@ class UpdatesPresenter(
             val deletedUpdates = uiModels.filter {
                 it is UpdatesUiModel.Item && deletedIds.contains(it.item.update.chapterId)
             }
-            if (deletedUpdates.isEmpty()) return@launchIO
+            if (deletedUpdates.isEmpty()) return@launchNonCancellableIO
 
             // TODO: Don't do this fake status update
             state.uiModels = uiModels.toMutableList().apply {

+ 13 - 10
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt

@@ -32,7 +32,7 @@ import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
 import eu.kanade.tachiyomi.ui.base.controller.pushController
 import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController
 import eu.kanade.tachiyomi.util.CrashLogUtil
-import eu.kanade.tachiyomi.util.lang.launchIO
+import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.preference.bindTo
 import eu.kanade.tachiyomi.util.preference.defaultValue
@@ -89,7 +89,9 @@ class SettingsAdvancedController(
             summaryRes = R.string.pref_dump_crash_logs_summary
 
             onClick {
-                CrashLogUtil(context).dumpLogs()
+                viewScope.launchNonCancellableIO {
+                    CrashLogUtil(context).dumpLogs()
+                }
             }
         }
 
@@ -340,7 +342,7 @@ class SettingsAdvancedController(
 
     private fun clearChapterCache() {
         val activity = activity ?: return
-        launchIO {
+        viewScope.launchNonCancellableIO {
             try {
                 val deletedFiles = chapterCache.clear()
                 withUIContext {
@@ -358,12 +360,13 @@ class SettingsAdvancedController(
     private fun clearWebViewData() {
         val activity = activity ?: return
         try {
-            val webview = WebView(activity)
-            webview.setDefaultSettings()
-            webview.clearCache(true)
-            webview.clearFormData()
-            webview.clearHistory()
-            webview.clearSslPreferences()
+            WebView(activity).run {
+                setDefaultSettings()
+                clearCache(true)
+                clearFormData()
+                clearHistory()
+                clearSslPreferences()
+            }
             WebStorage.getInstance().deleteAllData()
             activity.applicationInfo?.dataDir?.let { File("$it/app_webview/").deleteRecursively() }
             activity.toast(R.string.webview_data_deleted)
@@ -375,7 +378,7 @@ class SettingsAdvancedController(
 
     private fun resetViewerFlags() {
         val activity = activity ?: return
-        launchIO {
+        viewScope.launchNonCancellableIO {
             val success = mangaRepository.resetViewerFlags()
             withUIContext {
                 val message = if (success) {

+ 8 - 11
app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt

@@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.BuildConfig
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 import eu.kanade.tachiyomi.data.notification.Notifications
-import eu.kanade.tachiyomi.util.lang.launchIO
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.storage.getUriCompat
 import eu.kanade.tachiyomi.util.system.createFileInCacheDir
@@ -21,17 +20,15 @@ class CrashLogUtil(private val context: Context) {
         setSmallIcon(R.drawable.ic_tachi)
     }
 
-    fun dumpLogs() {
-        launchIO {
-            try {
-                val file = context.createFileInCacheDir("tachiyomi_crash_logs.txt")
-                Runtime.getRuntime().exec("logcat *:E -d -f ${file.absolutePath}").waitFor()
-                file.appendText(getDebugInfo())
+    suspend fun dumpLogs() {
+        try {
+            val file = context.createFileInCacheDir("tachiyomi_crash_logs.txt")
+            Runtime.getRuntime().exec("logcat *:E -d -f ${file.absolutePath}").waitFor()
+            file.appendText(getDebugInfo())
 
-                showNotification(file.getUriCompat(context))
-            } catch (e: Throwable) {
-                withUIContext { context.toast("Failed to get logs") }
-            }
+            showNotification(file.getUriCompat(context))
+        } catch (e: Throwable) {
+            withUIContext { context.toast("Failed to get logs") }
         }
     }
 

+ 0 - 14
app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt

@@ -24,20 +24,6 @@ object ChapterSettingsHelper {
     /**
      * Updates a single manga's Chapter Settings to match what's set in Preferences.
      */
-    fun applySettingDefaults(manga: Manga) {
-        launchIO {
-            setMangaChapterFlags.awaitSetAllFlags(
-                mangaId = manga.id,
-                unreadFilter = preferences.filterChapterByRead().toLong(),
-                downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
-                bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
-                sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
-                sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
-                displayMode = preferences.displayChapterByNameOrNumber().toLong(),
-            )
-        }
-    }
-
     suspend fun applySettingDefaults(mangaId: Long) {
         setMangaChapterFlags.awaitSetAllFlags(
             mangaId = mangaId,

+ 4 - 0
app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt

@@ -6,6 +6,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.NonCancellable
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
@@ -48,6 +49,9 @@ fun CoroutineScope.launchUI(block: suspend CoroutineScope.() -> Unit): Job =
 fun CoroutineScope.launchIO(block: suspend CoroutineScope.() -> Unit): Job =
     launch(Dispatchers.IO, block = block)
 
+fun CoroutineScope.launchNonCancellableIO(block: suspend CoroutineScope.() -> Unit): Job =
+    launchIO { withContext(NonCancellable, block) }
+
 suspend fun <T> withUIContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block)
 
 suspend fun <T> withIOContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block)