diff --git a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt index 82796b75e..27bbcabbf 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt @@ -60,6 +60,7 @@ import com.hippo.ehviewer.util.AppConfig import com.hippo.ehviewer.util.CrashHandler import com.hippo.ehviewer.util.FavouriteStatusRouter import com.hippo.ehviewer.util.FileUtils +import com.hippo.ehviewer.util.OSUtils import com.hippo.ehviewer.util.isAtLeastO import com.hippo.ehviewer.util.isAtLeastP import com.hippo.ehviewer.util.isAtLeastS @@ -107,7 +108,8 @@ class EhApplication : launchUI { FavouriteStatusRouter.collect { (gid, slot) -> detailCache[gid]?.favoriteSlot = slot } } launch { EhTagDatabase } launch { EhDB } - dataStateFlow.value + launchIO { dataStateFlow.value } + launchIO { OSUtils.totalMemory } launch { if (DownloadManager.labelList.isNotEmpty() && Settings.downloadFilterMode.key !in Settings.prefs) { Settings.downloadFilterMode.value = DownloadsFilterMode.CUSTOM.flag @@ -118,13 +120,9 @@ class EhApplication : FileUtils.cleanupDirectory(AppConfig.externalCrashDir) FileUtils.cleanupDirectory(AppConfig.externalParseErrorDir) } - launch { - cleanupDownload() - } + launch { cleanupDownload() } if (Settings.requestNews) { - launch { - checkDawn() - } + launch { checkDawn() } } } if (BuildConfig.DEBUG) { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/coil/QrCodeInterceptor.kt b/app/src/main/kotlin/com/hippo/ehviewer/coil/QrCodeInterceptor.kt index 02aabb2dc..ffa226ebe 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/coil/QrCodeInterceptor.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/coil/QrCodeInterceptor.kt @@ -13,6 +13,7 @@ import com.hippo.ehviewer.Settings import com.hippo.ehviewer.image.hasQrCode import eu.kanade.tachiyomi.util.system.logcat import moe.tarsin.coroutines.runSuspendCatching +import moe.tarsin.kt.sync private val detectQrCodeKey = Extras.Key(default = false) @@ -33,7 +34,7 @@ object QrCodeInterceptor : Interceptor { if (image is BitmapImageWithExtraInfo) { fun compute() = runSuspendCatching { hasQrCode(image.image.bitmap) }.onFailure { logcat(it) }.getOrThrow() val hasQrCode = when (val key = result.memoryCacheKey) { - is MemoryCache.Key -> synchronized(cache) { cache[key] } ?: compute().also { synchronized(cache) { cache[key] = it } } + is MemoryCache.Key -> cache.sync { cache[key] } ?: compute().also { cache.sync { cache[key] = it } } null -> compute() } val new = image.copy(hasQrCode = hasQrCode) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt b/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt index 592cc17a8..66a1dea8a 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt @@ -6,32 +6,30 @@ import com.hippo.ehviewer.Settings import com.hippo.ehviewer.image.Image import com.hippo.ehviewer.util.OSUtils import com.hippo.ehviewer.util.isAtLeastO -import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update +import moe.tarsin.kt.sync private const val MAX_CACHE_SIZE = 512 * 1024 * 1024 private const val MIN_CACHE_SIZE = 128 * 1024 * 1024 abstract class PageLoader { - private val cache by lazy { - SieveCache( - maxSize = if (isAtLeastO) { - (OSUtils.totalMemory / 16).toInt().coerceIn(MIN_CACHE_SIZE, MAX_CACHE_SIZE) + private val cache = SieveCache( + maxSize = if (isAtLeastO) { + (OSUtils.totalMemory / 16).toInt().coerceIn(MIN_CACHE_SIZE, MAX_CACHE_SIZE) + } else { + (OSUtils.appMaxMemory / 3 * 2).toInt() + }, + sizeOf = { _, v -> v.allocationSize.toInt() }, + onEntryRemoved = { k, o, n, _ -> + if (o.isRecyclable) { + n ?: notifyPageWait(k) + o.recycle() } else { - (OSUtils.appMaxMemory / 3 * 2).toInt() - }, - sizeOf = { _, v -> v.allocationSize.toInt() }, - onEntryRemoved = { k, o, n, _ -> - if (o.isRecyclable) { - n ?: notifyPageWait(k) - o.recycle() - } else { - o.isRecyclable = true - } - }, - ) - } + o.isRecyclable = true + } + }, + ) val pages by lazy { check(size > 0) @@ -41,10 +39,7 @@ abstract class PageLoader { private val prefetchPageCount = Settings.preloadImage @CallSuper - open suspend fun awaitReady(): Boolean { - withIOContext { cache } - return true - } + open suspend fun awaitReady() = true abstract val isReady: Boolean @@ -53,11 +48,11 @@ abstract class PageLoader { @CallSuper open fun stop() { - cache.evictAll() + cache.sync { evictAll() } } fun restart() { - cache.evictAll() + cache.sync { evictAll() } pages.forEach(Page::reset) } @@ -66,7 +61,7 @@ abstract class PageLoader { private var lastRequestIndex = -1 fun request(index: Int) { - val image = cache[index] + val image = cache.sync { cache[index] } if (image != null) { notifyPageSucceed(index, image, false) } else { @@ -125,7 +120,7 @@ abstract class PageLoader { fun notifyPageSucceed(index: Int, image: Image, replaceCache: Boolean = true) { if (replaceCache) { - cache.put(index, image) + cache.sync { cache[index] = image } } pages[index].statusFlow.update { if (image.hasQrCode) PageStatus.Blocked(image) else PageStatus.Ready(image) } } diff --git a/app/src/main/kotlin/moe/tarsin/kt/Sync.kt b/app/src/main/kotlin/moe/tarsin/kt/Sync.kt new file mode 100644 index 000000000..69380c63a --- /dev/null +++ b/app/src/main/kotlin/moe/tarsin/kt/Sync.kt @@ -0,0 +1,3 @@ +package moe.tarsin.kt + +inline fun T.sync(block: T.() -> R) = synchronized(this) { block(this) }