Просмотр исходного кода

fix: 优化主题字体加载性能

HapeLee 3 месяцев назад
Родитель
Сommit
0a6658c61e
1 измененных файлов с 31 добавлено и 16 удалено
  1. 31 16
      app/src/main/java/io/legado/app/ui/theme/ThemeComponents.kt

+ 31 - 16
app/src/main/java/io/legado/app/ui/theme/ThemeComponents.kt

@@ -1,8 +1,10 @@
 package io.legado.app.ui.theme
 
+import android.content.Context
 import android.graphics.Typeface
 import android.net.Uri
 import android.os.Build
+import android.util.LruCache
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.MaterialExpressiveTheme
 import androidx.compose.material3.MotionScheme
@@ -10,40 +12,53 @@ import androidx.compose.material3.Shapes
 import androidx.compose.material3.Typography
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.produceState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.text.font.FontFamily
 import io.legado.app.domain.model.settings.customColors
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
 import top.yukonga.miuix.kmp.theme.ColorSchemeMode
 import top.yukonga.miuix.kmp.theme.MiuixTheme
 import top.yukonga.miuix.kmp.theme.ThemeController
 
 @Composable
 fun rememberCustomFont(fontPath: String?): FontFamily? {
-    val context = LocalContext.current
-    return remember(fontPath, context) {
-        if (!fontPath.isNullOrEmpty()) {
-            try {
-                val uri = Uri.parse(fontPath)
-                val typeface: Typeface? = if (uri.scheme == "content") {
-                    context.contentResolver.openFileDescriptor(uri, "r")?.use {
-                        Typeface.Builder(it.fileDescriptor).build()
+    val context = LocalContext.current.applicationContext
+    val cachedFont = remember(fontPath) {
+        fontPath?.let { synchronized(customFontCache) { customFontCache.get(it) } }
+    }
+    return produceState(cachedFont, fontPath, context) {
+        if (value == null) {
+            value = fontPath?.takeIf(String::isNotBlank)?.let { path ->
+                withContext(Dispatchers.IO) {
+                    loadCustomFont(context, path)?.also { fontFamily ->
+                        synchronized(customFontCache) { customFontCache.put(path, fontFamily) }
                     }
-                } else {
-                    Typeface.createFromFile(uri.path)
                 }
-                typeface?.let { FontFamily(it) }
-            } catch (e: Exception) {
-                null
             }
-        } else {
-            null
         }
-    }
+    }.value
 }
 
+private val customFontCache = LruCache<String, FontFamily>(4)
+
+private fun loadCustomFont(context: Context, fontPath: String): FontFamily? =
+    runCatching {
+        val uri = Uri.parse(fontPath)
+        val typeface = if (uri.scheme == "content") {
+            context.contentResolver.openFileDescriptor(uri, "r")?.use {
+                Typeface.Builder(it.fileDescriptor).build()
+            }
+        } else {
+            Typeface.createFromFile(uri.path)
+        }
+        typeface?.let(::FontFamily)
+    }.getOrNull()
+
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
 fun MiuixThemeWrapper(