From 3fc05b03f5104e910e285fccc80290213a283ad8 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Fri, 2 Sep 2022 21:50:44 +0600 Subject: [PATCH] Lessen the use of GlobalScope `launchIO` (#7916) * Lessen the use of GlobalScope `launchIO` * Wrap some calls with `NonCancellable` context (cherry picked from commit da95ecb6869314f35eb73c6d9245b4e0d127f22d) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt --- .../source/browse/BrowseSourcePresenter.kt | 2 +- .../tachiyomi/ui/library/LibraryPresenter.kt | 9 +++--- .../tachiyomi/ui/manga/MangaPresenter.kt | 29 +++++++++---------- .../tachiyomi/ui/reader/ReaderPresenter.kt | 19 ++++++------ .../ui/recent/updates/UpdatesPresenter.kt | 7 +++-- .../ui/setting/SettingsAdvancedController.kt | 23 ++++++++------- .../eu/kanade/tachiyomi/util/CrashLogUtil.kt | 19 +++++------- .../util/chapter/ChapterSettingsHelper.kt | 14 --------- .../util/lang/CoroutinesExtensions.kt | 4 +++ 9 files changed, 59 insertions(+), 67 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index 13d916663..77981eca6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -323,7 +323,7 @@ open class BrowseSourcePresenter( if (!new.favorite) { new = new.removeCovers(coverCache) } else { - ChapterSettingsHelper.applySettingDefaults(manga) + ChapterSettingsHelper.applySettingDefaults(manga.id) autoAddTrack(manga) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index e4d07dd42..5af0ba4c3 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -63,6 +63,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.lang.withIOContext import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State @@ -726,7 +727,7 @@ class LibraryPresenter( * @param mangas the list of manga. */ fun downloadUnreadChapters(mangas: List) { - launchIO { + presenterScope.launchNonCancellableIO { mangas.forEach { manga -> if (manga.source == MERGED_SOURCE_ID) { val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource @@ -796,7 +797,7 @@ class LibraryPresenter( * @param mangas the list of manga. */ fun markReadStatus(mangas: List, read: Boolean) { - launchIO { + presenterScope.launchNonCancellableIO { mangas.forEach { manga -> setReadStatus.await( manga = manga, @@ -814,7 +815,7 @@ class LibraryPresenter( * @param deleteChapters whether to delete downloaded chapters. */ fun removeMangas(mangaList: List, deleteFromLibrary: Boolean, deleteChapters: Boolean) { - launchIO { + presenterScope.launchNonCancellableIO { val mangaToDelete = mangaList.distinctBy { it.id } if (deleteFromLibrary) { @@ -854,7 +855,7 @@ class LibraryPresenter( * @param removeCategories the categories to remove in all mangas. */ fun setMangaCategories(mangaList: List, addCategories: List, removeCategories: List) { - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { mangaList.map { manga -> val categoryIds = getCategories.await(manga.id) .map { it.id } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 4cf7e3ce1..144b95a76 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -63,6 +63,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 @@ -799,7 +800,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) { @@ -816,7 +816,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?) { @@ -1123,7 +1122,7 @@ class MangaPresenter( * @param chapters the list of chapters to delete. */ fun deleteChapters(chapters: List) { - launchIO { + presenterScope.launchNonCancellableIO { val chapters2 = chapters.map { it.toDbChapter() } try { updateSuccessState { successState -> @@ -1155,10 +1154,10 @@ class MangaPresenter( } private fun downloadNewChapters(chapters: List) { - 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) || manga.isEhBasedManga()) return@launchIO + if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(categories, preferences) || manga.isEhBasedManga()) return@launchNonCancellableIO downloadChapters(chapters) } } @@ -1175,7 +1174,7 @@ class MangaPresenter( State.INCLUDE -> DomainManga.CHAPTER_SHOW_UNREAD State.EXCLUDE -> DomainManga.CHAPTER_SHOW_READ } - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { setMangaChapterFlags.awaitSetUnreadFilter(manga, flag) } } @@ -1193,7 +1192,7 @@ class MangaPresenter( State.EXCLUDE -> DomainManga.CHAPTER_SHOW_NOT_DOWNLOADED } - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { setMangaChapterFlags.awaitSetDownloadedFilter(manga, flag) } } @@ -1211,7 +1210,7 @@ class MangaPresenter( State.EXCLUDE -> DomainManga.CHAPTER_SHOW_NOT_BOOKMARKED } - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { setMangaChapterFlags.awaitSetBookmarkFilter(manga, flag) } } @@ -1232,7 +1231,7 @@ class MangaPresenter( fun setDisplayMode(mode: Long) { val manga = successState?.manga ?: return - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { setMangaChapterFlags.awaitSetDisplayMode(manga, mode) } } @@ -1244,7 +1243,7 @@ class MangaPresenter( fun setSorting(sort: Long) { val manga = successState?.manga ?: return - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { setMangaChapterFlags.awaitSetSortingModeOrFlipOrder(manga, sort) } } @@ -1389,7 +1388,7 @@ class MangaPresenter( fun refreshTrackers() { refreshTrackersJob?.cancel() - refreshTrackersJob = launchIO { + refreshTrackersJob = presenterScope.launchNonCancellableIO { supervisorScope { try { trackList @@ -1439,7 +1438,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 } @@ -1481,13 +1480,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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 0965b6ce4..f9a67f45c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -54,6 +54,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 @@ -275,7 +276,7 @@ class ReaderPresenter( */ fun onSaveInstanceStateNonConfigurationChange() { val currentChapter = getCurrentChapter() ?: return - launchIO { + presenterScope.launchNonCancellableIO { saveChapterProgress(currentChapter) } } @@ -615,7 +616,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) } @@ -696,7 +697,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(), @@ -831,7 +832,7 @@ class ReaderPresenter( // Copy file in background. try { - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { val uri = imageSaver.save( image = Image.Page( inputStream = page.stream!!, @@ -935,7 +936,7 @@ class ReaderPresenter( val filename = generateFilename(manga, page) try { - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { destDir.deleteRecursively() val uri = imageSaver.save( image = Image.Page( @@ -991,7 +992,7 @@ class ReaderPresenter( val manga = manga?.toDomainManga() ?: return val stream = page.stream ?: return - presenterScope.launchIO { + presenterScope.launchNonCancellableIO { try { manga.editCover(context, stream()) withUIContext { @@ -1037,7 +1038,7 @@ class ReaderPresenter( val trackManager = Injekt.get() val context = Injekt.get() - launchIO { + presenterScope.launchNonCancellableIO { getTracks.await(manga.id!!) .mapNotNull { track -> val service = trackManager.getService(track.syncId) @@ -1081,7 +1082,7 @@ class ReaderPresenter( } ?: return // SY <-- - launchIO { + presenterScope.launchNonCancellableIO { downloadManager.enqueueDeleteChapters(listOf(chapter.chapter), manga.toDomainManga()!!) } } @@ -1091,7 +1092,7 @@ class ReaderPresenter( * are ignored. */ private fun deletePendingChapters() { - launchIO { + presenterScope.launchNonCancellableIO { downloadManager.deletePendingChapters() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt index fcf7afb87..9de0964c4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt +++ b/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 @@ -223,7 +224,7 @@ class UpdatesPresenter( * @param updatesItem the list of chapters to download. */ fun downloadChapters(updatesItem: List) { - launchIO { + presenterScope.launchNonCancellableIO { val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values for (updates in groupedUpdates) { val mangaId = updates.first().update.mangaId @@ -242,7 +243,7 @@ class UpdatesPresenter( * @param updatesItem list of chapters */ fun deleteChapters(updatesItem: List) { - launchIO { + presenterScope.launchNonCancellableIO { val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values val deletedIds = groupedUpdates.flatMap { updates -> val mangaId = updates.first().update.mangaId @@ -255,7 +256,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 { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt index 34aee19ec..8e0064788 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt @@ -45,7 +45,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 @@ -102,7 +102,9 @@ class SettingsAdvancedController( summaryRes = R.string.pref_dump_crash_logs_summary onClick { - CrashLogUtil(context).dumpLogs() + viewScope.launchNonCancellableIO { + CrashLogUtil(context).dumpLogs() + } } } @@ -582,7 +584,7 @@ class SettingsAdvancedController( private fun clearChapterCache() { val activity = activity ?: return - launchIO { + viewScope.launchNonCancellableIO { try { val deletedFiles = chapterCache.clear() withUIContext { @@ -600,12 +602,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) @@ -617,7 +620,7 @@ class SettingsAdvancedController( private fun resetViewerFlags() { val activity = activity ?: return - launchIO { + viewScope.launchNonCancellableIO { val success = mangaRepository.resetViewerFlags() withUIContext { val message = if (success) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt index 5e7e0b55b..7a1c7cec8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt +++ b/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 @@ -22,17 +21,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") } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt index c5748b96f..dbef6ab2f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt +++ b/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, diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt index 930272116..31eef3cff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt +++ b/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 withUIContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block) suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block)