From 071b597552a5fb687ef45997b0ba1b8c28485c74 Mon Sep 17 00:00:00 2001 From: tarsin Date: Fri, 19 May 2023 17:06:32 +0800 Subject: [PATCH] Introduce rememberMemorized --- .../ehviewer/ui/compose/RememberGlobally.kt | 34 +++++++++++++++---- .../ehviewer/ui/scene/GalleryPreviewScreen.kt | 4 +-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/compose/RememberGlobally.kt b/app/src/main/java/com/hippo/ehviewer/ui/compose/RememberGlobally.kt index 53006df56..2c7ae4df8 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/compose/RememberGlobally.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/compose/RememberGlobally.kt @@ -1,15 +1,17 @@ package com.hippo.ehviewer.ui.compose -import androidx.collection.lruCache import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.currentCompositeKeyHash import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.saveable.LocalSaveableStateRegistry -private val remembered = lruCache(1) +private val remembered = hashMapOf() +// This works mostly like [rememberSaveable], but saves data in global hashmap, to avoid [TransactionTooLargeException] @Composable -fun rememberGlobally( +fun rememberMemorized( vararg inputs: Any?, key: String? = null, init: () -> T, @@ -20,15 +22,33 @@ fun rememberGlobally( } else { currentCompositeKeyHash.toString(36) } + + val registry = LocalSaveableStateRegistry.current // value is restored using the registry or created via [init] lambda val value = remember(*inputs) { @Suppress("UNCHECKED_CAST") - val restored = remembered[finalKey] as? T + val restored = registry?.consumeRestored(finalKey)?.let { + remembered.remove(it as String) + } as? T restored ?: init() } - LaunchedEffect(finalKey) { - remembered.put(finalKey, value) + // re-register if the registry or key has been changed + if (registry != null) { + // we want to use the latest instances of saver and value in the valueProvider lambda + // without restarting DisposableEffect as it would cause re-registering the provider in + // the different order. so we use rememberUpdatedState. + val valueState = rememberUpdatedState(value) + + DisposableEffect(registry, finalKey) { + val valueProvider = { + finalKey.also { remembered[it] = valueState.value } + } + val entry = registry.registerProvider(finalKey, valueProvider) + onDispose { + entry.unregister() + } + } } return value } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt index b9563e6a4..93fb75cce 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt @@ -57,7 +57,7 @@ import com.hippo.ehviewer.coil.imageRequest import com.hippo.ehviewer.coil.justDownload import com.hippo.ehviewer.ui.compose.data.EhPreviewItem import com.hippo.ehviewer.ui.compose.rememberDialogState -import com.hippo.ehviewer.ui.compose.rememberGlobally +import com.hippo.ehviewer.ui.compose.rememberMemorized import com.hippo.ehviewer.ui.compose.setMD3Content import com.hippo.ehviewer.ui.legacy.recyclerview.calculateSuitableSpanCount import com.hippo.ehviewer.ui.navToReader @@ -119,7 +119,7 @@ class GalleryPreviewScreen : Fragment() { initialKey = goto } - val previewPagesMap = rememberGlobally { mutableMapOf().apply { put(1, galleryDetail.previewList) } } + val previewPagesMap = rememberMemorized { mutableMapOf().apply { put(1, galleryDetail.previewList) } } val data = remember(initialKey) { Pager(PagingConfig(1, prefetchDistance = 4, enablePlaceholders = false, initialLoadSize = 1), initialKey) { object : PagingSource() {