mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +08:00
Modify merge YukiHookPrefsBridge cache function to LruCache and add new PreferencesCacheManager
This commit is contained in:
@@ -404,6 +404,8 @@ fun edit(): Editor
|
|||||||
|
|
||||||
> 创建新的 `Editor`。
|
> 创建新的 `Editor`。
|
||||||
|
|
||||||
|
在模块环境中或启用了 `isUsingNativeStorage` 后使用。
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
|
||||||
在 (Xposed) 宿主环境下只读,无法使用。
|
在 (Xposed) 宿主环境下只读,无法使用。
|
||||||
@@ -426,6 +428,8 @@ fun edit(initiate: Editor.() -> Unit)
|
|||||||
|
|
||||||
自动调用 `Editor.apply` 方法。
|
自动调用 `Editor.apply` 方法。
|
||||||
|
|
||||||
|
在模块环境中或启用了 `isUsingNativeStorage` 后使用。
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
|
||||||
在 (Xposed) 宿主环境下只读,无法使用。
|
在 (Xposed) 宿主环境下只读,无法使用。
|
||||||
@@ -444,16 +448,12 @@ fun clearCache()
|
|||||||
|
|
||||||
**Function Illustrate**
|
**Function Illustrate**
|
||||||
|
|
||||||
> 清除 `XSharedPreferences` 中缓存的键值数据。
|
> 清除 `YukiHookPrefsBridge` 中缓存的键值数据。
|
||||||
|
|
||||||
无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。
|
无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。
|
||||||
|
|
||||||
调用此方法将清除当前存储的全部键值缓存。
|
调用此方法将清除当前存储的全部键值缓存。
|
||||||
|
|
||||||
下次将从 `XSharedPreferences` 重新读取。
|
|
||||||
|
|
||||||
在 (Xposed) 宿主环境中使用。
|
|
||||||
|
|
||||||
## Editor <span class="symbol">- class</span>
|
## Editor <span class="symbol">- class</span>
|
||||||
|
|
||||||
```kotlin:no-line-numbers
|
```kotlin:no-line-numbers
|
||||||
@@ -470,6 +470,8 @@ inner class Editor internal constructor()
|
|||||||
|
|
||||||
请使用 `edit` 方法来获取 `Editor`。
|
请使用 `edit` 方法来获取 `Editor`。
|
||||||
|
|
||||||
|
在模块环境中或启用了 `isUsingNativeStorage` 后使用。
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
|
||||||
在 (Xposed) 宿主环境下只读,无法使用。
|
在 (Xposed) 宿主环境下只读,无法使用。
|
||||||
|
@@ -396,6 +396,8 @@ fun edit(): Editor
|
|||||||
|
|
||||||
> 创建新的 `Editor`。
|
> 创建新的 `Editor`。
|
||||||
|
|
||||||
|
在模块环境中或启用了 `isUsingNativeStorage` 后使用。
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
|
||||||
在 (Xposed) 宿主环境下只读,无法使用。
|
在 (Xposed) 宿主环境下只读,无法使用。
|
||||||
@@ -418,6 +420,8 @@ fun edit(initiate: Editor.() -> Unit)
|
|||||||
|
|
||||||
自动调用 `Editor.apply` 方法。
|
自动调用 `Editor.apply` 方法。
|
||||||
|
|
||||||
|
在模块环境中或启用了 `isUsingNativeStorage` 后使用。
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
|
||||||
在 (Xposed) 宿主环境下只读,无法使用。
|
在 (Xposed) 宿主环境下只读,无法使用。
|
||||||
@@ -436,16 +440,12 @@ fun clearCache()
|
|||||||
|
|
||||||
**功能描述**
|
**功能描述**
|
||||||
|
|
||||||
> 清除 `XSharedPreferences` 中缓存的键值数据。
|
> 清除 `YukiHookPrefsBridge` 中缓存的键值数据。
|
||||||
|
|
||||||
无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。
|
无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。
|
||||||
|
|
||||||
调用此方法将清除当前存储的全部键值缓存。
|
调用此方法将清除当前存储的全部键值缓存。
|
||||||
|
|
||||||
下次将从 `XSharedPreferences` 重新读取。
|
|
||||||
|
|
||||||
在 (Xposed) 宿主环境中使用。
|
|
||||||
|
|
||||||
## Editor <span class="symbol">- class</span>
|
## Editor <span class="symbol">- class</span>
|
||||||
|
|
||||||
```kotlin:no-line-numbers
|
```kotlin:no-line-numbers
|
||||||
@@ -462,6 +462,8 @@ inner class Editor internal constructor()
|
|||||||
|
|
||||||
请使用 `edit` 方法来获取 `Editor`。
|
请使用 `edit` 方法来获取 `Editor`。
|
||||||
|
|
||||||
|
在模块环境中或启用了 `isUsingNativeStorage` 后使用。
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
|
||||||
在 (Xposed) 宿主环境下只读,无法使用。
|
在 (Xposed) 宿主环境下只读,无法使用。
|
||||||
|
@@ -39,6 +39,7 @@ import com.highcapable.yukihookapi.hook.log.yLoggerW
|
|||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.delegate.XSharedPreferencesDelegate
|
import com.highcapable.yukihookapi.hook.xposed.bridge.delegate.XSharedPreferencesDelegate
|
||||||
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.prefs.cache.PreferencesCacheManager
|
||||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||||
import com.highcapable.yukihookapi.hook.xposed.prefs.ui.ModulePreferenceFragment
|
import com.highcapable.yukihookapi.hook.xposed.prefs.ui.ModulePreferenceFragment
|
||||||
import de.robv.android.xposed.XSharedPreferences
|
import de.robv.android.xposed.XSharedPreferences
|
||||||
@@ -108,49 +109,12 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
else "${YukiXposedModule.modulePackageName.ifBlank { context?.packageName ?: "unknown" }}_preferences"
|
else "${YukiXposedModule.modulePackageName.ifBlank { context?.packageName ?: "unknown" }}_preferences"
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 是否使用键值缓存 */
|
|
||||||
private var isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
|
|
||||||
|
|
||||||
/** 是否使用新版存储方式 EdXposed、LSPosed */
|
/** 是否使用新版存储方式 EdXposed、LSPosed */
|
||||||
private var isUsingNewXSharedPreferences = false
|
private var isUsingNewXSharedPreferences = false
|
||||||
|
|
||||||
/** 是否启用原生存储方式 */
|
/** 是否启用原生存储方式 */
|
||||||
private var isUsingNativeStorage = false
|
private var isUsingNativeStorage = false
|
||||||
|
|
||||||
/**
|
|
||||||
* [XSharedPreferences] 缓存的键值数据
|
|
||||||
*/
|
|
||||||
private object XSharedPreferencesCaches {
|
|
||||||
|
|
||||||
/** 缓存的 [String] 键值数据 */
|
|
||||||
var stringData = ArrayMap<String, String>()
|
|
||||||
|
|
||||||
/** 缓存的 [Set]<[String]> 键值数据 */
|
|
||||||
var stringSetData = ArrayMap<String, Set<String>>()
|
|
||||||
|
|
||||||
/** 缓存的 [Boolean] 键值数据 */
|
|
||||||
var booleanData = ArrayMap<String, Boolean>()
|
|
||||||
|
|
||||||
/** 缓存的 [Int] 键值数据 */
|
|
||||||
var intData = ArrayMap<String, Int>()
|
|
||||||
|
|
||||||
/** 缓存的 [Long] 键值数据 */
|
|
||||||
var longData = ArrayMap<String, Long>()
|
|
||||||
|
|
||||||
/** 缓存的 [Float] 键值数据 */
|
|
||||||
var floatData = ArrayMap<String, Float>()
|
|
||||||
|
|
||||||
/** 清除所有缓存的键值数据 */
|
|
||||||
fun clear() {
|
|
||||||
stringData.clear()
|
|
||||||
stringSetData.clear()
|
|
||||||
booleanData.clear()
|
|
||||||
intData.clear()
|
|
||||||
longData.clear()
|
|
||||||
floatData.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 检查 API 装载状态 */
|
/** 检查 API 装载状态 */
|
||||||
private fun checkApi() {
|
private fun checkApi() {
|
||||||
if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookPrefsBridge not allowed in Custom Hook API")
|
if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookPrefsBridge not allowed in Custom Hook API")
|
||||||
@@ -202,6 +166,12 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
if (isUsingNewXSharedPreferences.not()) makeWorldReadable(context, prefsFileName = "${currentPrefsName}.xml")
|
if (isUsingNewXSharedPreferences.not()) makeWorldReadable(context, prefsFileName = "${currentPrefsName}.xml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前 [PreferencesCacheManager] 对象
|
||||||
|
* @return [PreferencesCacheManager]
|
||||||
|
*/
|
||||||
|
private val cacheManager get() = PreferencesCacheManager.instance()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 [XSharedPreferences] 是否可读
|
* 获取 [XSharedPreferences] 是否可读
|
||||||
*
|
*
|
||||||
@@ -247,7 +217,7 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [YukiHookPrefsBridge]
|
* @return [YukiHookPrefsBridge]
|
||||||
*/
|
*/
|
||||||
fun name(name: String): YukiHookPrefsBridge {
|
fun name(name: String): YukiHookPrefsBridge {
|
||||||
isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
|
cacheManager.enableByConfig()
|
||||||
prefsName = name
|
prefsName = name
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -261,7 +231,7 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [YukiHookPrefsBridge]
|
* @return [YukiHookPrefsBridge]
|
||||||
*/
|
*/
|
||||||
fun direct(): YukiHookPrefsBridge {
|
fun direct(): YukiHookPrefsBridge {
|
||||||
isUsingKeyValueCache = false
|
cacheManager.disable()
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,19 +258,11 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
fun getString(key: String, value: String = "") =
|
fun getString(key: String, value: String = "") =
|
||||||
(if (isXposedEnvironment && isUsingNativeStorage.not())
|
cacheManager.getString(key) {
|
||||||
if (isUsingKeyValueCache)
|
if (isXposedEnvironment && isUsingNativeStorage.not())
|
||||||
XSharedPreferencesCaches.stringData[key].let {
|
currentXsp.getString(key, value) ?: value
|
||||||
(it ?: currentXsp.getString(key, value) ?: value).let { value ->
|
else currentSp.getString(key, value) ?: value
|
||||||
XSharedPreferencesCaches.stringData[key] = value
|
}.also { makeWorldReadable() }
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else resetCacheSet { currentXsp.getString(key, value) ?: value }
|
|
||||||
else currentSp.getString(key, value) ?: value).let {
|
|
||||||
makeWorldReadable()
|
|
||||||
it
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 [Set]<[String]> 键值
|
* 获取 [Set]<[String]> 键值
|
||||||
@@ -309,23 +271,15 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
*
|
*
|
||||||
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
|
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
|
||||||
* @param key 键值名称
|
* @param key 键值名称
|
||||||
* @param value 默认数据
|
* @param value 默认数据 - [HashSet]<[String]>
|
||||||
* @return [Set]<[String]>
|
* @return [Set]<[String]>
|
||||||
*/
|
*/
|
||||||
fun getStringSet(key: String, value: Set<String>) =
|
fun getStringSet(key: String, value: Set<String> = hashSetOf()) =
|
||||||
(if (isXposedEnvironment && isUsingNativeStorage.not())
|
cacheManager.getStringSet(key) {
|
||||||
if (isUsingKeyValueCache)
|
if (isXposedEnvironment && isUsingNativeStorage.not())
|
||||||
XSharedPreferencesCaches.stringSetData[key].let {
|
currentXsp.getStringSet(key, value) ?: value
|
||||||
(it ?: currentXsp.getStringSet(key, value) ?: value).let { value ->
|
else currentSp.getStringSet(key, value) ?: value
|
||||||
XSharedPreferencesCaches.stringSetData[key] = value
|
}.also { makeWorldReadable() }
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else resetCacheSet { currentXsp.getStringSet(key, value) ?: value }
|
|
||||||
else currentSp.getStringSet(key, value) ?: value).let {
|
|
||||||
makeWorldReadable()
|
|
||||||
it
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 [Boolean] 键值
|
* 获取 [Boolean] 键值
|
||||||
@@ -338,19 +292,11 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [Boolean]
|
* @return [Boolean]
|
||||||
*/
|
*/
|
||||||
fun getBoolean(key: String, value: Boolean = false) =
|
fun getBoolean(key: String, value: Boolean = false) =
|
||||||
(if (isXposedEnvironment && isUsingNativeStorage.not())
|
cacheManager.getBoolean(key) {
|
||||||
if (isUsingKeyValueCache)
|
if (isXposedEnvironment && isUsingNativeStorage.not())
|
||||||
XSharedPreferencesCaches.booleanData[key].let {
|
currentXsp.getBoolean(key, value)
|
||||||
it ?: currentXsp.getBoolean(key, value).let { value ->
|
else currentSp.getBoolean(key, value)
|
||||||
XSharedPreferencesCaches.booleanData[key] = value
|
}.also { makeWorldReadable() }
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else resetCacheSet { currentXsp.getBoolean(key, value) }
|
|
||||||
else currentSp.getBoolean(key, value)).let {
|
|
||||||
makeWorldReadable()
|
|
||||||
it
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 [Int] 键值
|
* 获取 [Int] 键值
|
||||||
@@ -363,19 +309,11 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [Int]
|
* @return [Int]
|
||||||
*/
|
*/
|
||||||
fun getInt(key: String, value: Int = 0) =
|
fun getInt(key: String, value: Int = 0) =
|
||||||
(if (isXposedEnvironment && isUsingNativeStorage.not())
|
cacheManager.getInt(key) {
|
||||||
if (isUsingKeyValueCache)
|
if (isXposedEnvironment && isUsingNativeStorage.not())
|
||||||
XSharedPreferencesCaches.intData[key].let {
|
currentXsp.getInt(key, value)
|
||||||
it ?: currentXsp.getInt(key, value).let { value ->
|
else currentSp.getInt(key, value)
|
||||||
XSharedPreferencesCaches.intData[key] = value
|
}.also { makeWorldReadable() }
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else resetCacheSet { currentXsp.getInt(key, value) }
|
|
||||||
else currentSp.getInt(key, value)).let {
|
|
||||||
makeWorldReadable()
|
|
||||||
it
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 [Float] 键值
|
* 获取 [Float] 键值
|
||||||
@@ -388,19 +326,11 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [Float]
|
* @return [Float]
|
||||||
*/
|
*/
|
||||||
fun getFloat(key: String, value: Float = 0f) =
|
fun getFloat(key: String, value: Float = 0f) =
|
||||||
(if (isXposedEnvironment && isUsingNativeStorage.not())
|
cacheManager.getFloat(key) {
|
||||||
if (isUsingKeyValueCache)
|
if (isXposedEnvironment && isUsingNativeStorage.not())
|
||||||
XSharedPreferencesCaches.floatData[key].let {
|
currentXsp.getFloat(key, value)
|
||||||
it ?: currentXsp.getFloat(key, value).let { value ->
|
else currentSp.getFloat(key, value)
|
||||||
XSharedPreferencesCaches.floatData[key] = value
|
}.also { makeWorldReadable() }
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else resetCacheSet { currentXsp.getFloat(key, value) }
|
|
||||||
else currentSp.getFloat(key, value)).let {
|
|
||||||
makeWorldReadable()
|
|
||||||
it
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 [Long] 键值
|
* 获取 [Long] 键值
|
||||||
@@ -413,19 +343,11 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @return [Long]
|
* @return [Long]
|
||||||
*/
|
*/
|
||||||
fun getLong(key: String, value: Long = 0L) =
|
fun getLong(key: String, value: Long = 0L) =
|
||||||
(if (isXposedEnvironment && isUsingNativeStorage.not())
|
cacheManager.getLong(key) {
|
||||||
if (isUsingKeyValueCache)
|
if (isXposedEnvironment && isUsingNativeStorage.not())
|
||||||
XSharedPreferencesCaches.longData[key].let {
|
currentXsp.getLong(key, value)
|
||||||
it ?: currentXsp.getLong(key, value).let { value ->
|
else currentSp.getLong(key, value)
|
||||||
XSharedPreferencesCaches.longData[key] = value
|
}.also { makeWorldReadable() }
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else resetCacheSet { currentXsp.getLong(key, value) }
|
|
||||||
else currentSp.getLong(key, value)).let {
|
|
||||||
makeWorldReadable()
|
|
||||||
it
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 智能获取指定类型的键值
|
* 智能获取指定类型的键值
|
||||||
@@ -596,7 +518,7 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
/**
|
/**
|
||||||
* 创建新的 [Editor]
|
* 创建新的 [Editor]
|
||||||
*
|
*
|
||||||
* - 在模块环境中使用
|
* - 在模块环境中或启用了 [isUsingNativeStorage] 后使用
|
||||||
*
|
*
|
||||||
* - ❗在 (Xposed) 宿主环境下只读 - 无法使用
|
* - ❗在 (Xposed) 宿主环境下只读 - 无法使用
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
@@ -608,42 +530,28 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
*
|
*
|
||||||
* 自动调用 [Editor.apply] 方法
|
* 自动调用 [Editor.apply] 方法
|
||||||
*
|
*
|
||||||
* - 在模块环境中使用
|
* - 在模块环境中或启用了 [isUsingNativeStorage] 后使用
|
||||||
*
|
*
|
||||||
* - ❗在 (Xposed) 宿主环境下只读 - 无法使用
|
* - ❗在 (Xposed) 宿主环境下只读 - 无法使用
|
||||||
* @param initiate 方法体
|
* @param initiate 方法体
|
||||||
*/
|
*/
|
||||||
fun edit(initiate: Editor.() -> Unit = {}) = edit().apply(initiate).apply()
|
fun edit(initiate: Editor.() -> Unit) = edit().apply(initiate).apply()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除 [XSharedPreferences] 中缓存的键值数据
|
* 清除 [YukiHookPrefsBridge] 中缓存的键值数据
|
||||||
*
|
*
|
||||||
* 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache]
|
* 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache]
|
||||||
*
|
*
|
||||||
* 调用此方法将清除当前存储的全部键值缓存
|
* 调用此方法将清除当前存储的全部键值缓存
|
||||||
*
|
|
||||||
* 下次将从 [XSharedPreferences] 重新读取
|
|
||||||
*
|
|
||||||
* - 在 (Xposed) 宿主环境中使用
|
|
||||||
*/
|
*/
|
||||||
fun clearCache() = XSharedPreferencesCaches.clear()
|
fun clearCache() = cacheManager.edit().clear().apply()
|
||||||
|
|
||||||
/**
|
|
||||||
* 恢复 [isUsingKeyValueCache] 为默认状态
|
|
||||||
* @param result 回调方法体的结果
|
|
||||||
* @return [T]
|
|
||||||
*/
|
|
||||||
private inline fun <T> resetCacheSet(result: () -> T): T {
|
|
||||||
isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
|
|
||||||
return result()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [YukiHookPrefsBridge] 的存储代理类
|
* [YukiHookPrefsBridge] 的存储代理类
|
||||||
*
|
*
|
||||||
* - ❗请使用 [edit] 方法来获取 [Editor]
|
* - ❗请使用 [edit] 方法来获取 [Editor]
|
||||||
*
|
*
|
||||||
* - 在模块环境中使用
|
* - 在模块环境中或启用了 [isUsingNativeStorage] 后使用
|
||||||
*
|
*
|
||||||
* - ❗在 (Xposed) 宿主环境下只读 - 无法使用
|
* - ❗在 (Xposed) 宿主环境下只读 - 无法使用
|
||||||
*/
|
*/
|
||||||
@@ -652,13 +560,17 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
/** 创建新的存储代理类 */
|
/** 创建新的存储代理类 */
|
||||||
private var editor = runCatching { currentSp.edit() }.getOrNull()
|
private var editor = runCatching { currentSp.edit() }.getOrNull()
|
||||||
|
|
||||||
|
/** 创建 [PreferencesCacheManager] 存储代理类 */
|
||||||
|
private var cacheEditor = cacheManager.edit()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除全部包含 [key] 的存储数据
|
* 移除全部包含 [key] 的存储数据
|
||||||
* @param key 键值名称
|
* @param key 键值名称
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun remove(key: String) = moduleEnvironment {
|
fun remove(key: String) = specifiedScope {
|
||||||
editor?.remove(key)
|
editor?.remove(key)
|
||||||
|
cacheEditor.remove(key)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,8 +585,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* 移除全部存储数据
|
* 移除全部存储数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun clear() = moduleEnvironment {
|
fun clear() = specifiedScope {
|
||||||
editor?.clear()
|
editor?.clear()
|
||||||
|
cacheEditor.clear()
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,8 +599,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @param value 键值数据
|
* @param value 键值数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun putString(key: String, value: String) = moduleEnvironment {
|
fun putString(key: String, value: String) = specifiedScope {
|
||||||
editor?.putString(key, value)
|
editor?.putString(key, value)
|
||||||
|
cacheEditor.updateString(key, value)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,8 +613,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @param value 键值数据
|
* @param value 键值数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun putStringSet(key: String, value: Set<String>) = moduleEnvironment {
|
fun putStringSet(key: String, value: Set<String>) = specifiedScope {
|
||||||
editor?.putStringSet(key, value)
|
editor?.putStringSet(key, value)
|
||||||
|
cacheEditor.updateStringSet(key, value)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,8 +627,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @param value 键值数据
|
* @param value 键值数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun putBoolean(key: String, value: Boolean) = moduleEnvironment {
|
fun putBoolean(key: String, value: Boolean) = specifiedScope {
|
||||||
editor?.putBoolean(key, value)
|
editor?.putBoolean(key, value)
|
||||||
|
cacheEditor.updateBoolean(key, value)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,8 +641,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @param value 键值数据
|
* @param value 键值数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun putInt(key: String, value: Int) = moduleEnvironment {
|
fun putInt(key: String, value: Int) = specifiedScope {
|
||||||
editor?.putInt(key, value)
|
editor?.putInt(key, value)
|
||||||
|
cacheEditor.updateInt(key, value)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,8 +655,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @param value 键值数据
|
* @param value 键值数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun putFloat(key: String, value: Float) = moduleEnvironment {
|
fun putFloat(key: String, value: Float) = specifiedScope {
|
||||||
editor?.putFloat(key, value)
|
editor?.putFloat(key, value)
|
||||||
|
cacheEditor.updateFloat(key, value)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,8 +669,9 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* @param value 键值数据
|
* @param value 键值数据
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
fun putLong(key: String, value: Long) = moduleEnvironment {
|
fun putLong(key: String, value: Long) = specifiedScope {
|
||||||
editor?.putLong(key, value)
|
editor?.putLong(key, value)
|
||||||
|
cacheEditor.updateLong(key, value)
|
||||||
makeWorldReadable()
|
makeWorldReadable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -787,19 +706,19 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
|||||||
* 提交更改 (同步)
|
* 提交更改 (同步)
|
||||||
* @return [Boolean] 是否成功
|
* @return [Boolean] 是否成功
|
||||||
*/
|
*/
|
||||||
fun commit() = editor?.commit()?.also { makeWorldReadable() } ?: false
|
fun commit() = editor?.commit()?.also { cacheEditor.apply(); makeWorldReadable() } ?: false
|
||||||
|
|
||||||
/** 提交更改 (异步) */
|
/** 提交更改 (异步) */
|
||||||
fun apply() = editor?.apply().also { makeWorldReadable() } ?: Unit
|
fun apply() = editor?.apply().also { cacheEditor.apply(); makeWorldReadable() } ?: Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仅在模块环境执行
|
* 仅在模块环境或 [isUsingNativeStorage] 执行
|
||||||
*
|
*
|
||||||
* 非模块环境使用会打印警告信息
|
* 非模块环境使用会打印警告信息
|
||||||
* @param callback 在模块环境执行
|
* @param callback 在模块环境执行
|
||||||
* @return [Editor]
|
* @return [Editor]
|
||||||
*/
|
*/
|
||||||
private inline fun moduleEnvironment(callback: () -> Unit): Editor {
|
private inline fun specifiedScope(callback: () -> Unit): Editor {
|
||||||
if (isXposedEnvironment.not() || isUsingNativeStorage) callback()
|
if (isXposedEnvironment.not() || isUsingNativeStorage) callback()
|
||||||
else yLoggerW(msg = "YukiHookPrefsBridge.Editor not allowed in Xposed Environment")
|
else yLoggerW(msg = "YukiHookPrefsBridge.Editor not allowed in Xposed Environment")
|
||||||
return this
|
return this
|
||||||
|
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* YukiHookAPI - An efficient Hook API and Xposed Module solution built in Kotlin.
|
||||||
|
* Copyright (C) 2019-2023 HighCapable
|
||||||
|
* https://github.com/fankes/YukiHookAPI
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is Created by fankes on 2023/4/20.
|
||||||
|
*/
|
||||||
|
package com.highcapable.yukihookapi.hook.xposed.prefs.cache
|
||||||
|
|
||||||
|
import com.highcapable.yukihookapi.YukiHookAPI
|
||||||
|
import com.highcapable.yukihookapi.hook.utils.memory.factory.createLruCache
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [YukiHookPrefsBridge] 缓存管理类
|
||||||
|
*/
|
||||||
|
internal class PreferencesCacheManager private constructor() {
|
||||||
|
|
||||||
|
internal companion object {
|
||||||
|
|
||||||
|
/** 当前 [PreferencesCacheManager] 单例 */
|
||||||
|
private var instance: PreferencesCacheManager? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 [PreferencesCacheManager] 单例
|
||||||
|
* @return [PreferencesCacheManager]
|
||||||
|
*/
|
||||||
|
internal fun instance() = instance ?: PreferencesCacheManager().apply { instance = this }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否使用键值缓存功能 */
|
||||||
|
private var isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
|
||||||
|
|
||||||
|
private val stringData = createLruCache<String, String>()
|
||||||
|
private val stringSetData = createLruCache<String, Set<String>>()
|
||||||
|
private val booleanData = createLruCache<String, Boolean>()
|
||||||
|
private val intData = createLruCache<String, Int>()
|
||||||
|
private val longData = createLruCache<String, Long>()
|
||||||
|
private val floatData = createLruCache<String, Float>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的 [String] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 无缓存获取回调
|
||||||
|
*/
|
||||||
|
internal fun getString(key: String, value: () -> String) =
|
||||||
|
if (isUsingKeyValueCache) stringData.get(key) ?: resetCacheSet { value().also { stringData.put(key, it) } } else value()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的 [Set]<[String]> 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 无缓存获取回调
|
||||||
|
*/
|
||||||
|
internal fun getStringSet(key: String, value: () -> Set<String>) =
|
||||||
|
if (isUsingKeyValueCache) stringSetData.get(key) ?: resetCacheSet { value().also { stringSetData.put(key, it) } } else value()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的 [Boolean] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 无缓存获取回调
|
||||||
|
*/
|
||||||
|
internal fun getBoolean(key: String, value: () -> Boolean) =
|
||||||
|
if (isUsingKeyValueCache) booleanData.get(key) ?: resetCacheSet { value().also { booleanData.put(key, it) } } else value()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的 [Int] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 无缓存获取回调
|
||||||
|
*/
|
||||||
|
internal fun getInt(key: String, value: () -> Int) =
|
||||||
|
if (isUsingKeyValueCache) intData.get(key) ?: resetCacheSet { value().also { intData.put(key, it) } } else value()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的 [Long] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 无缓存获取回调
|
||||||
|
*/
|
||||||
|
internal fun getLong(key: String, value: () -> Long) =
|
||||||
|
if (isUsingKeyValueCache) longData.get(key) ?: resetCacheSet { value().also { longData.put(key, it) } } else value()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的 [Float] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 无缓存获取回调
|
||||||
|
*/
|
||||||
|
internal fun getFloat(key: String, value: () -> Float) =
|
||||||
|
if (isUsingKeyValueCache) floatData.get(key) ?: resetCacheSet { value().also { floatData.put(key, it) } } else value()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建新的 [Editor]
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun edit() = Editor()
|
||||||
|
|
||||||
|
/** 启用缓存功能 - 跟随 [YukiHookAPI.Configs.isEnablePrefsBridgeCache] 控制 */
|
||||||
|
internal fun enableByConfig() {
|
||||||
|
isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 禁用缓存功能 */
|
||||||
|
internal fun disable() {
|
||||||
|
isUsingKeyValueCache = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PreferencesCacheManager] 的存储代理类
|
||||||
|
*
|
||||||
|
* - ❗请使用 [edit] 方法来获取 [Editor]
|
||||||
|
*/
|
||||||
|
internal inner class Editor internal constructor() {
|
||||||
|
|
||||||
|
/** 预提交任务数组 */
|
||||||
|
private val preSubmitTasks = HashSet<() -> Unit>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存的 [String] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun updateString(key: String, value: String): Editor {
|
||||||
|
if (isUsingKeyValueCache) preSubmitTasks.add { stringData.put(key, value) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存的 [Set]<[String]> 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun updateStringSet(key: String, value: Set<String>): Editor {
|
||||||
|
if (isUsingKeyValueCache) preSubmitTasks.add { stringSetData.put(key, value) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存的 [Boolean] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun updateBoolean(key: String, value: Boolean): Editor {
|
||||||
|
if (isUsingKeyValueCache) preSubmitTasks.add { booleanData.put(key, value) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存的 [Int] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun updateInt(key: String, value: Int): Editor {
|
||||||
|
if (isUsingKeyValueCache) preSubmitTasks.add { intData.put(key, value) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存的 [Long] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun updateLong(key: String, value: Long): Editor {
|
||||||
|
if (isUsingKeyValueCache) preSubmitTasks.add { longData.put(key, value) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新缓存的 [Float] 键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun updateFloat(key: String, value: Float): Editor {
|
||||||
|
if (isUsingKeyValueCache) preSubmitTasks.add { floatData.put(key, value) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除缓存的键值
|
||||||
|
* @param key 键值名称
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun remove(key: String): Editor {
|
||||||
|
if (isUsingKeyValueCache) runCatching {
|
||||||
|
if (stringSetData.get(key) != null) preSubmitTasks.add { stringData.remove(key) }
|
||||||
|
if (stringSetData.get(key) != null) preSubmitTasks.add { stringSetData.remove(key) }
|
||||||
|
if (booleanData.get(key) != null) preSubmitTasks.add { booleanData.remove(key) }
|
||||||
|
if (intData.get(key) != null) preSubmitTasks.add { intData.remove(key) }
|
||||||
|
if (longData.get(key) != null) preSubmitTasks.add { longData.remove(key) }
|
||||||
|
if (floatData.get(key) != null) preSubmitTasks.add { floatData.remove(key) }
|
||||||
|
}; return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除所有缓存的键值数据
|
||||||
|
* @return [Editor]
|
||||||
|
*/
|
||||||
|
internal fun clear(): Editor {
|
||||||
|
preSubmitTasks.add {
|
||||||
|
stringData.evictAll()
|
||||||
|
stringSetData.evictAll()
|
||||||
|
booleanData.evictAll()
|
||||||
|
intData.evictAll()
|
||||||
|
longData.evictAll()
|
||||||
|
floatData.evictAll()
|
||||||
|
}; return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 提交更改 */
|
||||||
|
internal fun apply() {
|
||||||
|
preSubmitTasks.takeIf { it.isNotEmpty() }?.onEach { it() }?.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复 [isUsingKeyValueCache] 为默认状态
|
||||||
|
* @param result 回调方法体的结果
|
||||||
|
* @return [T]
|
||||||
|
*/
|
||||||
|
private inline fun <T> resetCacheSet(result: () -> T): T {
|
||||||
|
enableByConfig()
|
||||||
|
return result()
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user