mirror of
https://github.com/mihonapp/mihon.git
synced 2026-10-19 23:22:26 -07:00
Move blocking work off the main thread and fix threading races (#4068)
* Defer startup work until first use * Move cover work off the main thread * Make tracker calls main-safe and token refresh thread-safe Kitsu, Shikimori and MangaBaka refresh their token under a lock like MAL, so parallel calls no longer refresh it twice. * Fix extension threading and make installs cancellable The store service read response bodies on Main, which failed with NetworkOnMainThreadException for http stores. * Move reader work off the main thread and save progress in order * Serialize the downloader and fix download threading * Stop blocking on WorkManager status queries Also removes NotificationReceiver's open chapter action: nothing sends it, and its handler used runBlocking. * Start migration jobs on the migrator's dispatcher They started undispatched, so each ran on the caller's thread until its first suspension. * Run screen and view model work on fitting dispatchers * Launch work that outlives a screen on the app scope A launch on another dispatcher is dropped if the screen closes before it starts, which dialogs that dismiss right away often do. Only the UI follow-up stays on viewModelScope. * Remove the coroutine helper extensions They hid which dispatcher and scope a call used, and the GlobalScope ones hid that it was global.
This commit is contained in:
@@ -15,9 +15,11 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.SMangaUpdate
|
||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.atStartOfDayIn
|
||||
@@ -31,7 +33,6 @@ import nl.adaptivity.xmlutil.serialization.XML
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
import tachiyomi.core.common.storage.extension
|
||||
import tachiyomi.core.common.storage.nameWithoutExtension
|
||||
import tachiyomi.core.common.util.lang.withIOContext
|
||||
import tachiyomi.core.common.util.system.ImageUtil
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE
|
||||
@@ -86,7 +87,9 @@ class LocalSource(
|
||||
|
||||
override suspend fun getLatestUpdates(page: Int) = getSearchManga(page, "", LatestFilters)
|
||||
|
||||
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage = withIOContext {
|
||||
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage = withContext(
|
||||
Dispatchers.IO,
|
||||
) {
|
||||
val lastModifiedLimit = if (filters === LatestFilters) {
|
||||
System.currentTimeMillis() - LATEST_THRESHOLD
|
||||
} else {
|
||||
@@ -160,7 +163,7 @@ class LocalSource(
|
||||
}
|
||||
|
||||
// Manga details related
|
||||
private suspend fun getMangaDetails(manga: SManga): SManga = withIOContext {
|
||||
private suspend fun getMangaDetails(manga: SManga): SManga = withContext(Dispatchers.IO) {
|
||||
coverManager.find(manga.url)?.let {
|
||||
manga.thumbnail_url = it.uri.toString()
|
||||
}
|
||||
@@ -224,7 +227,7 @@ class LocalSource(
|
||||
logcat(LogPriority.ERROR, e) { "Error setting manga details from local metadata for ${manga.title}" }
|
||||
}
|
||||
|
||||
return@withIOContext manga
|
||||
return@withContext manga
|
||||
}
|
||||
|
||||
private fun <T> getComicInfoForChapter(chapter: UniFile, block: (InputStream) -> T): T? {
|
||||
@@ -287,7 +290,7 @@ class LocalSource(
|
||||
}
|
||||
|
||||
// Chapters
|
||||
private suspend fun getChapterList(manga: SManga): List<SChapter> = withIOContext {
|
||||
private suspend fun getChapterList(manga: SManga): List<SChapter> = withContext(Dispatchers.IO) {
|
||||
val chapters = fileSystem.getFilesInMangaDirectory(manga.url)
|
||||
// Only keep supported formats
|
||||
.filterNot { it.name.orEmpty().startsWith('.') }
|
||||
|
||||
Reference in New Issue
Block a user