前言

我平时用java写的sp工具类,现在有两个需求:

第一个是要管理sp的文件名,虽然java可以通过Config的方式配置几个final静态的字符串常量来管理,但是总感觉不够优雅,而且可能存在随便写个文件名,不放在Config内的情况

第二个是要一次保存多个数据的话,java需要多次调用,emmm,不够优雅

效果

还是先看kt调用的代码

同时向USER_INFO_CACHE文件中写入两个数据

从USER_INFO_CACHE文件中读取数据,并设置默认值

清空USER_INFO_CACHE文件中的数据

同时从USER_INFO_CACHE文件读取多条String数据

使用属性委托,快捷操作sp中的数据

代码

工具类代码,直接粘贴到一个kt文件内

重构后的:

/*** creator: lt  2019/7/13--15:40    lt.dygzs@qq.com* effect : SharedPreferences工具类* warning:*//*** 往sp中写入数据,this为fileName*/
fun SpName.writeSP(bean: Pair<String, *>): SpName {App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE).edit().put(bean).apply()return this
}fun SpName.writeSPs(vararg beans: Pair<String, *>): SpName {if (beans.isEmpty()) {throw RuntimeException("writeSPs没有填写可变参数")}val editor = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE).edit()beans.map(editor::put)editor.apply()return this
}//处理存储类型
private fun SharedPreferences.Editor.put(bean: Pair<String, *>): SharedPreferences.Editor {when (bean.second) {is Boolean -> this.putBoolean(bean.first, bean.second as Boolean)is Int -> this.putInt(bean.first, bean.second as Int)is Long -> this.putLong(bean.first, bean.second as Long)is Float -> this.putFloat(bean.first, bean.second as Float)is String -> this.putString(bean.first, bean.second as String)is Number -> this.putString(bean.first, bean.second.toString())else -> this.putString(bean.first, bean.second.toJson())//toJson()是利用Gosn或者fastJson把对象变为json数据}return this
}/*** 从sp中读取数据,this为fileName* 注意读取数值和boolean的时候最好给个默认值*/
fun <T> SpName.readSP(key: String, defaultValue: T): T {val preference = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE)return when (defaultValue) {is Boolean -> preference.getBoolean(key, defaultValue)is Int -> preference.getInt(key, defaultValue)is Long -> preference.getLong(key, defaultValue)is Float -> preference.getFloat(key, defaultValue)is String -> preference.getString(key, defaultValue)is Byte -> preference.getString(key, defaultValue.toString()).toByte()is Short -> preference.getString(key, defaultValue.toString()).toShort()is Double -> preference.getString(key, defaultValue.toString()).toDouble()is UByte -> preference.getString(key, defaultValue.toString()).toUByte()is UShort -> preference.getString(key, defaultValue.toString()).toUShort()is UInt -> preference.getString(key, defaultValue.toString()).toUInt()is ULong -> preference.getString(key, defaultValue.toString()).toULong()else -> throw RuntimeException("如果读取对象,请使用string类型的默认值,或者使用内联的readSPOfAny方法")} as T
}/*** 从sp中读取对象,this为fileName* 注意,如果json读不到则会返回null对象*/
inline fun <reified T> SpName.readSPOfAny(key: String): T? {if (T::class.java == String::class.java|| T::class.java == Boolean::class.java|| T::class.java == Number::class.java)throw RuntimeException("读取sp中的数据时,类型不正确,readSPOfAny方法只能用来读取对象")return this.readSP(key, "").json2Any()
}/*** 同时读取多条数据* 注意:需要读取同一种类型,若读取不同类型需要分开读取*      传入的Bean的key为key value为默认值*/
inline fun <reified T> SpName.readSPs(vararg beans: Pair<String, T>): Array<T> {if (beans.isEmpty()) {throw RuntimeException("readSPs没有填写可变参数")}return Array(beans.size) {this@readSPs.readSP(beans[it].first, beans[it].second)}
}/*** 清空该sp文件中的所有内容*/
fun SpName.clearSP(): SpName {App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE).edit().clear().apply()return this
}/*** 移除相应key的数据*/
fun SpName.removeSP(vararg keys: String): SpName {if (keys.isEmpty()) {throw RuntimeException("removeSP没有填写可变参数")}val edit = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE).edit()keys.map(edit::remove)edit.apply()return this
}/*** 快捷创建一个s - t 的Pair 使用方式:s/t*/
operator fun <T> String.div(value: T): Pair<String, T> = Pair(this, value)

重构前的(看你怎么选了):

/*** creator: lt  2019/7/13--15:40    lt.dygzs@qq.com* effect : SharedPreferences工具类* warning: 暂时只支持 int boolean String 三种类型*/
//todo 注:下面的App.getInstance()方法是获取Application的上下文,童鞋使用时请自行替换
/*** 往sp中写入数据,this为fileName* 注意只接收 int String boolean*/
fun SpName.writeSP(vararg beans: SPSaveBean<*>) {val editor = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE).edit()beans.map {when (it.value) {is Int -> editor.putInt(it.key, it.value as Int)is Boolean -> editor.putBoolean(it.key, it.value as Boolean)is String -> editor.putString(it.key, it.value as String)else -> throw RuntimeException("向sp中写入时,类型不正确")}}editor.apply()
}/*** 从sp中读取数据,this为fileName* 注意只能读到 int String boolean* 注意读取int 和 boolean的时候最好给个默认值*/
fun <T> SpName.readSP(key: String, defaultValue: T): T {val preference = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE)return when (defaultValue) {is Int -> preference.getInt(key, defaultValue)is Boolean -> preference.getBoolean(key, defaultValue)is String -> preference.getString(key, defaultValue)else -> throw RuntimeException("读取sp中的数据时,类型不正确")} as T
}inline fun <reified T> SpName.readSP(key: String): T =this.readSP(key, when (T::class.java) {Int::class.java -> 0Boolean::class.java -> falseString::class.java -> ""else -> throw RuntimeException("读取sp中的数据时,类型不正确")} as T)/*** 同时读取多条数据* 注意:需要读取同一种类型,若读取不同类型需要分开读取*      传入的SPSaveBean的key为key value为默认值*/
inline fun <reified T> SpName.readSPs(vararg spBeans: SPSaveBean<T>): Array<T> {return Array(spBeans.size) {return@Array this@readSPs.readSP(spBeans[it].key, spBeans[it].value)}
}/*** 清空该sp文件中的所有内容*/
fun SpName.clearSP() {val sp = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE)sp.edit().clear().apply()
}/*** 移除相应key的数据*/
fun SpName.removeSP(vararg keys: String) {val sp = App.getInstance().getSharedPreferences(this, Context.MODE_PRIVATE)val edit = sp.edit()keys.map {edit.remove(it)}edit.apply()
}/*** creator:  lt  2019/7/13--15:54    lt.dygzs@qq.com* effect : 快捷使用SPUtil存储的bean* warning:*/
class SPSaveBean<T>(val key: String, val value: T)/*** 快捷创建一个s - s 的SPSaveBean 使用方式:s/s  下同*/
operator fun String.div(value: String): SPSaveBean<String> = SPSaveBean(this, value)operator fun String.div(value: Int): SPSaveBean<Int> = SPSaveBean(this, value)
operator fun String.div(value: Boolean): SPSaveBean<Boolean> = SPSaveBean(this, value)

SPFileName文件

/*** creator:  lt  2019/7/13--15:45    lt.dygzs@qq.com* effect : 存储sp文件的名字,写的时候加上用途* warning: 一个文件不要存储过多内容,影响效率*/
object SPFileName {@JvmFieldval USER_INFO_CACHE = SpName("userInfoCache")//用于存储用户信息
}class SpName(val value: String)

Kotlin委托的代码,可以更方便的使用sp

/*** 属性委托类,可以更方便的使用* 只可以获取基本类型* 如果key传空字符串,则使用自身的名字为key*/
class SP<T>(private val spName: SpName, private val defaultValue: T, private val key: String = "") {operator fun getValue(thisRef: Any?, property: KProperty<*>): T =spName.readSP(if (key == "") property.name else key, defaultValue)operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) =spName.writeSP((if (key == "") property.name else key) / value)
}//只可以委托对象
class SPAny<T>(val spName: SpName, val key: String = "") {inline operator fun <reified T> getValue(thisRef: Any?, property: KProperty<*>): T? =spName.readSPOfAny(if (key == "") property.name else key)operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) =spName.writeSP((if (key == "") property.name else key) / value)
}

SP委托的使用

使用by关键字声明一个SP委托:

获取和设置就像操作变量一样:

打印出:

上面的每次获取都会从sp中获取,而每次赋值都会向sp中写入,比直接操作sp更方便

解析

SpUtil还是那个SpUtil,但是中间用了几种Kotlin特性来封装了一下,操作和管理更方便

可能有几个可能不是太常见的地方,我简单说一下

1.SP的性能问题

sp有性能问题,这是一般都知道的,由于底层是使用的xml文件存储数据,所以冷读取和冷存储都是需要通过io流的,其xml文件存储在 data/data/包名/shared_prefs 下,而由于sp#edit#commit方法就是冷提交:在主线程中直接阻塞并提交数据变更,所以,如果一个sp文件中存储过多或过大的话,就有很大的可能会阻塞主线程,所以提交改用sp#edit#apply方法提交,是一个异步提交方法,具体实现可以自行百度

2. 字符串 斜杠 字符串  是个什么写法?

是kt的操作符重载,参考下面链接第六条,当然你看会了可以改成其他的操作符

https://blog.csdn.net/qq_33505109/article/details/81031791

3.typealias SpName = String 是什么意思?

是kt的类型别名,参考下面链接第九条

https://blog.csdn.net/qq_33505109/article/details/81031791

4.val (v1,v2)=readSPs() 是什么操作?

是kt的解构声明,其实返回的就是一个泛型数组,参考下面链接第一条

https://blog.csdn.net/qq_33505109/article/details/81031791

Kotlin优雅的使用sp(SharedPreferences)相关推荐

  1. Java之于Kotlin对比(Android)

    前言 通过一段时间对Kotlin的使用,总结一下Android版kotlin各种语法的写法 顺便发几个常用工具类的写法,希望大家指正 正文 ######1. Thread Java写法 new Thr ...

  2. Kotlin binding+RecyclerView实现支付宝首页更多、应用编辑界面

    activity 主布局页面: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xm ...

  3. Kotlin Weekly 中文周报

    Kotlin Weekly 中文周报 -- 25 Kotlin 开发中文周报 文章 使用 Kotlin 中的 takeIf (zhuanlan.zhihu.com) 在 Kotlin 的标准函数中有个 ...

  4. sharedpreferences使用方法_细数 SharedPreferences 的那些槽点 !

    前言 最近在处理一个历史遗留项目的时候饱受其害,主要表现为偶发性的 SharedPreferences 配置文件数据错乱,甚至丢失.经过排查发现是多进程的问题.项目中有两个不同进程,且会频繁的读写 S ...

  5. 『後起Android开发02』对SharedPreferences和Toast的简单封装

    转载请注明,原文地址:http://blog.csdn.net/liu17ezlyy 偶尔看到一些老外的代码,总感觉他们写太好了,很赞.我技术一般,没有这么大的能耐,只能简单优化一下我认为能缩减的代码 ...

  6. java 读取rom文件_Android -- 读写文件到内部ROM,SD卡,SharedPreferences,文件读写权限...

    (内容整理自张泽华教程) 1. 概述 使用文件进行数据存储 首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过 ...

  7. kotlin中Activity跳转

    问题描述: override fun onClick(widget: View) {val intent = Intent(AActivity.this, BActivity::class.java) ...

  8. android用SP,判断是否过了一天

    思路:打开的时候缓存一个时间,如果当前的时间比保存的时间大,就是第二天. PS:用sp会有个漏洞,如果客户把缓存清理了,再打开,还是会执行第二天的事件,或者用户改了android的系统时间,也一样. ...

  9. 细数 SharedPreferences 的那些槽点 !

    前言 最近在处理一个历史遗留项目的时候饱受其害,主要表现为偶发性的 SharedPreferences 配置文件数据错乱,甚至丢失.经过排查发现是多进程的问题.项目中有两个不同进程,且会频繁的读写 S ...

最新文章

  1. 使用ContentProvider
  2. 跨域理解及服务器端解决跨域问题
  3. 基础才是重中之重~用好configSections让配置信息更规范
  4. Gensim Word2vec 使用教程
  5. Hello Blazor:(13)查找HTML元素对应.razor文件
  6. 安装和使用Ant Design Vue 图标库
  7. React- jsx的使用可以渲染html标签 或React组件
  8. 超级抖音腾讯视频V3.6.0小程序源码 前端+后端 支持视频采集和上传
  9. php pdo批量操作,PDO使用二维数组批量操作MYSQL数据库
  10. 关于机器人方面的sci论文_如何给论文润色?从这两个方面入手
  11. python笔记02_面向对象编程和面向对象高级编程
  12. 开关电源测试系统用哪个软件,开关电源测试系统
  13. python pandas series加速原理_python pandas中对Series数据进行轴向连接的实例
  14. 光流(八)--总结篇
  15. 鸿蒙移植mate10,鸿蒙系统+麒麟1020再升一个台阶,华为Mate30黯然神伤无奈下跌
  16. es 全量同步mysql_MySQL用得好好的,为什么要转ES?
  17. Iframe的allow属性生效时机
  18. 支付宝 android 崩溃,支付宝App崩溃网友集体炸锅 官方紧急回应
  19. java 获取年和季度_java获取当前时间的年周月季度等的开始结束时间
  20. 来曲唑十二烷基硫酸钠/苯丁酸氮芥/层状双金属氢氧化物纳米杂化物

热门文章

  1. tensorboardX笔记:理解graph
  2. NTU 课程 7454 (5) CNN进阶
  3. python文件操作2:在指定目录下查找指定后缀名的文件
  4. SSH框架联合开发(Annotation精简Spring的配置文件)
  5. C语言输入end时结束程序,给大家一个程序,输入多个字符串以END结束后排序,这个程序运行,即结果都是对的。...
  6. UNIX 网络协议的深度分析
  7. 服务发现框架选型,Consul还是Zookeeper还是etcd
  8. 美团配送资金安全治理之对账体系建设
  9. 今天犯的一个错误,导致method GET must not have a request body
  10. spring源码分析之spring-core asm概述