From 59468d1bc2cf4d8c3e2911c0d204f39a6ead7bcf Mon Sep 17 00:00:00 2001 From: Isilsolme Date: Sun, 31 May 2026 19:45:11 +0800 Subject: [PATCH 1/3] Fix language preference not persisting after app restart Use commit() instead of apply() for String preference writes to ensure the value is written to disk synchronously before the process is killed during restart(). Root cause: SharedPreferences.apply() writes to memory immediately but commits to disk asynchronously. When context.restart() calls Process.killProcess()+exitProcess(0) immediately after writing the language preference, the async disk write may not complete, causing the new process to read the old value. Closes #862 Co-Authored-By: Claude Opus 4.8 --- app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt | 5 +++-- app/src/main/java/io/legado/app/utils/ContextExtensions.kt | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt b/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt index 495fc67d5..9dad8c6f0 100644 --- a/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt @@ -12,11 +12,12 @@ import io.legado.app.utils.getPrefFloat import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefLong import io.legado.app.utils.getPrefString +import io.legado.app.utils.putPrefString import io.legado.app.utils.putPrefBoolean import io.legado.app.utils.putPrefFloat import io.legado.app.utils.putPrefInt import io.legado.app.utils.putPrefLong -import io.legado.app.utils.putPrefString +import io.legado.app.utils.putPrefStringSync import splitties.init.appCtx import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -84,7 +85,7 @@ fun prefDelegate( override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { if (_value.value != value) { when (value) { - is String? -> appCtx.putPrefString(key, value) + is String? -> appCtx.putPrefStringSync(key, value) is Int -> appCtx.putPrefInt(key, value) is Boolean -> appCtx.putPrefBoolean(key, value) is Long -> appCtx.putPrefLong(key, value) diff --git a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt index 41b26c2bf..d7ddc57c1 100644 --- a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt @@ -223,6 +223,9 @@ fun Context.getPrefString(key: String, defValue: String? = null) = fun Context.putPrefString(key: String, value: String?) = defaultSharedPreferences.edit { putString(key, value) } +fun Context.putPrefStringSync(key: String, value: String?) = + defaultSharedPreferences.edit(commit = true) { putString(key, value) } + fun Context.getPrefStringSet( key: String, defValue: MutableSet? = null, From 6ebe36dec9a46eafe48fba382c2518ed463491d2 Mon Sep 17 00:00:00 2001 From: Isilsolme Date: Sun, 31 May 2026 19:51:35 +0800 Subject: [PATCH 2/3] Refine: make synchronous pref writes opt-in via sync parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only use commit() (sync disk write) for preferences that opt in with sync=true. The language preference in OtherConfig is currently the only one that needs this — it triggers an immediate process restart via context.restart(). Other string preferences continue using apply() (async) to avoid unnecessary main-thread blocking. Co-Authored-By: Claude Opus 4.8 --- app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt | 6 ++++-- .../java/io/legado/app/ui/config/otherConfig/OtherConfig.kt | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt b/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt index 9dad8c6f0..d1bcf32d2 100644 --- a/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt @@ -35,6 +35,7 @@ fun prefDelegate( key: String, defaultValue: T, lifecycleOwner: LifecycleOwner? = null, + sync: Boolean = false, onValueChange: ((T) -> Unit)? = null ): PrefDelegate { return object : PrefDelegate, SharedPreferences.OnSharedPreferenceChangeListener, DefaultLifecycleObserver { @@ -85,7 +86,7 @@ fun prefDelegate( override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { if (_value.value != value) { when (value) { - is String? -> appCtx.putPrefStringSync(key, value) + is String? -> if (sync) appCtx.putPrefStringSync(key, value) else appCtx.putPrefString(key, value) is Int -> appCtx.putPrefInt(key, value) is Boolean -> appCtx.putPrefBoolean(key, value) is Long -> appCtx.putPrefLong(key, value) @@ -112,8 +113,9 @@ fun prefStateDelegate( key: String, defaultValue: T, lifecycleOwner: LifecycleOwner? = null, + sync: Boolean = false, onValueChange: ((T) -> Unit)? = null ): PrefStateDelegate { - val delegate = prefDelegate(key, defaultValue, lifecycleOwner, onValueChange) + val delegate = prefDelegate(key, defaultValue, lifecycleOwner, sync, onValueChange) return PrefStateDelegate(delegate) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfig.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfig.kt index 538b8bf64..0dd7d5ad6 100644 --- a/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfig.kt +++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfig.kt @@ -8,7 +8,8 @@ object OtherConfig { var language by prefDelegate( PreferKey.language, - "auto" + "auto", + sync = true ) var updateToVariant by prefDelegate( From 947dbbfff13cd18512be407fc06d44341ec009bd Mon Sep 17 00:00:00 2001 From: Isilsolme Date: Sun, 31 May 2026 20:52:05 +0800 Subject: [PATCH 3/3] Sort imports in PrefDelegate.kt Co-Authored-By: Claude Opus 4.8 --- app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt b/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt index d1bcf32d2..363ef981a 100644 --- a/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/config/PrefDelegate.kt @@ -12,11 +12,11 @@ import io.legado.app.utils.getPrefFloat import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefLong import io.legado.app.utils.getPrefString -import io.legado.app.utils.putPrefString import io.legado.app.utils.putPrefBoolean import io.legado.app.utils.putPrefFloat import io.legado.app.utils.putPrefInt import io.legado.app.utils.putPrefLong +import io.legado.app.utils.putPrefString import io.legado.app.utils.putPrefStringSync import splitties.init.appCtx import kotlin.properties.ReadWriteProperty