Kotlin 跨应用 多线程 轻量级配置存储方案

  • 卸载不删除
  • 需要外置存储读取权限
  • 用于Xposed插件配件也是很爽的
package com.meetunknown.up.Util.saved

import android.os.Environment
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.io.File
import java.util.*


object Saved {
    private val fileDir = try {
        Environment.getExternalStorageDirectory().absolutePath
    } catch (e: ArrayIndexOutOfBoundsException) {
        "/storage/emulated/0"
    }
    private val fileName = "tzs.json"

    private val filePath = fileDir + File.separator + fileName

    private  lateinit  var  mMap: ObserverableMap<String, Any>

    private val gson = GsonBuilder().setPrettyPrinting().create()

    private val mFile by lazy { File(filePath) }

    private var mLastModified: Long = -1L

    val obj = Object()

    init {
        syncFromFile()
    }


    private fun syncFromFile() {
        if (mFile.lastModified() != mLastModified) {
            val t = Thread {
                synchronized(obj) {
                    mFile.setReadable(true, false)
                    mFile.setWritable(true)
                    try {
                        if (mFile.exists().not() || mFile.readText().isNullOrEmpty()) {
                            mFile.createNewFile()
                            mMap = ObserverableMap()
                        } else {
                            mMap = gson.fromJson(mFile.readText(), object : TypeToken<ObserverableMap<String, Any>>() {}.type)
                        }
                        mMap.syncFromFile = { syncFromFile() }
                        mMap.syncToFile   = { syncToFile()   }
                    } catch (e: Exception) {

                    }
                    mLastModified = mFile.lastModified()
                    obj.notifyAll()
                }
            }
            t.name = "Meet-Load Saved"
            t.start()
        }
    }

    private fun syncToFile() {
        synchronized(obj){
            awaitLoaded()
            mFile.writeText(gson.toJson(mMap))
            mLastModified = mFile.lastModified()
            obj.notifyAll()
        }
    }

    private fun awaitLoaded() {
        while (mLastModified != mFile.lastModified() || !::mMap.isInitialized) {
            try {
                obj.wait()
            } catch (e: InterruptedException) {
            }

        }
    }

    private inline fun <T> syncAll(key:String,ok:((key:String)->T)):T{
        synchronized(obj) {
            awaitLoaded()
            return ok.invoke(key)
        }
    }

    fun contains(key: String): Boolean {
        return syncAll(key) { key in mMap }
    }



    fun getString(key: String, defaultValue: String = ""): String {
        synchronized(obj) {
            awaitLoaded()
            return (mMap[key] as String?) ?: defaultValue
        }

    }

    fun getInt(key: String, defaultValue: Int = 0): Int {
        synchronized(obj) {
            awaitLoaded()
            return ((mMap[key] as? Number)?.toInt()) ?: defaultValue
        }

    }

    fun getLong(key: String, defaultValue: Long = 0L): Long {

        synchronized(obj) {
            awaitLoaded()
            return ((mMap[key] as? Number)?.toLong()) ?: defaultValue
        }
    }

    fun getBoolean(key: String, defaultValue: Boolean = false): Boolean {
        synchronized(obj) {
            awaitLoaded()
            return mMap[key]?.toString()?.toBoolean() ?: defaultValue
        }
    }

    fun update(key:String, value:Any){
        synchronized(obj){
            awaitLoaded()
            mMap[key] = value
        }
    }

}


class ObserverableMap<K, T> : LinkedHashMap<K, T> {
    var syncFromFile: (() -> Unit)? = null
    var syncToFile:   (() -> Unit)? = null

    constructor() : super()
    constructor(p0: MutableMap<out K, out T>?) : super(p0)


    override fun remove(key: K): T? {
        syncFromFile?.invoke()
        return super.remove(key).also { syncToFile?.invoke() }
    }

    override fun get(key: K): T? {
        syncFromFile?.invoke()
        return super.get(key)
    }

    override fun put(key: K, value: T): T? {
        syncFromFile?.invoke()
        return super.put(key, value).also { syncToFile?.invoke() }
    }

    override fun clear() {
        super.clear().also { syncToFile?.invoke() }
    }

    override fun toString(): String {
        var temp = ""
        for (en in this.entries) {
            temp = temp.plus("${(en.value as Any)::class.qualifiedName!!.padEnd(40)}  ${(en.key as String).padEnd(20)}   ${en.value} \n")
        }
        return temp
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值