原文地址: 关于TornadoFx和Android的全局配置工具类封装实现及思路解析 - Stars-One的杂货小窝

目前个人开发软件存在设置页面,可以让用户自定义些设置,但我发现,存储数据的代码逻辑实在是有些繁琐(保存及APP打开的设置初始化)

于是便是花了些精力研究了些,封装了个简单的工具类,可以快捷实现存储数据的保存及初始化

目标

首先,我们知道,设置的选项值需要存放在本地,之后重新进入APP的时候,需要先从本地读取,若是本地读取不到,才赋予一个默认值

所以,确认下我们要达到的理想目标:

对于设置的某项数据,可以使用一个字段进行对应,而不用关心存储保存本地的更新操作和APP初始化读取数值的

实现步骤

先提及下思路,我们将数值保存的本地方法,其实无非就是使用File对象创建个文件,之后将数据写入文件接口实现配置

在TornadoFx中,提供了config对象供我们快速使用,而无需编写过多的关于文件流的操作的代码

PS:TornadoFx中,除了config,还有个Preference对象,但Preference是写入注册表的,所以这里我们不采用这种方式,详情可以看上一篇TornadoFx设置保存功能(config和preference使用) - Stars-One的杂货小窝

而在Android中,也是存在有个SharePreference的对象,可以存储写简单的数据

TornadoFx和Android的方法大同小异,我们以Android的方法为例讲解,后面会附有相关的源码,复制即可使用

1.实现本地存储数值

这里,由于是Android,使用了SharePreference对象来存储,由于SharePreference的使用需要Context参数,为了方便封装,用了个开源库,封装好了可以直接使用

以一个开关设置项为例(boolean数值),写个简单的类:

class GlobalDataConfig(val key:String) {
var flag = false fun setValue(newVal: Boolean) {
flag = newVal
updateLocalStorage(newVal)
} /**
*更新本地存储
*
* @param newVal
*/
private fun updateLocalStorage(newVal: Boolean) {
SPUtils.getInstance().put(key, newVal)
}
}

上面这样写,调用的时候,我们需要新建个类,然后设置去的初始值,之后更新统一走setValue()方法,里面已经包含了数据存储在本地的逻辑

PS: SPUtilsAndroidUtilCode库的工具类,用于快速设置SharePreference

如果按照上面的来的话,每个设置项都得新建个类,使用极其不优雅,我们接下来进行优化

2.任意数值(泛型)

首先,我们需要可以自定义任意类型的(虽然说是任意类型,其实最终还是得看SharePreference支持存储上面数据),一般我们用基本数据类型存储即可(存储对象的话就会十分麻烦)

那这个时候有个问题摆在眼前,我们如何获取用户传递的数值类型?

这个时候,泛型就派上用场了

我们可以这样写:

class GlobalDataConfig<T>(val key:String,var currentValue:T) {

    fun setValue(newVal: T) {
currentValue = newVal
updateLocalStorage(currentValue)
} /**
*更新本地存储
*
* @param newVal
*/
private fun updateLocalStorage(value: T) {
//各种类型的存储
if (value is Boolean) {
SPUtils.getInstance().put(key, value)
}
if (value is Float) {
SPUtils.getInstance().put(key, value)
}
if (value is String) {
SPUtils.getInstance().put(key, value)
}
if (value is Int) {
SPUtils.getInstance().put(key, value)
}
if (value is Long) {
SPUtils.getInstance().put(key, value)
}
}
}

这样,我们就可以通过构造函数来生成不同对象.来代表不同的数值项了

3.初始值

到了这步,我们还可以想到,进入APP的时候,配置项要进行初始化,这个时候应该是先从本地存储读取,若是读取不同,则是设置默认值

最初的想法是,使用个函数,用作初始化的数值读取,同时加个变量用来存储默认值(之后可以重置为默认值)

class GlobalDataConfig<T>(
val key:String,
var currentValue:T,
var defaultValue:T,
val lbd:((GlobalDataConfig<T>)->Unit)
) { init{
lbd.invoke(this)
} fun setValue(newVal: T) {
currentValue = newVal
updateLocalStorage(currentValue)
} /**
*更新本地存储
*
* @param newVal
*/
private fun updateLocalStorage(value: T) {
if (value is Boolean) {
SPUtils.getInstance().put(key, value)
}
if (value is Float) {
SPUtils.getInstance().put(key, value)
}
if (value is String) {
SPUtils.getInstance().put(key, value)
}
if (value is Int) {
SPUtils.getInstance().put(key, value)
}
if (value is Long) {
SPUtils.getInstance().put(key, value)
}
}
}

使用:

GlobalDataConfig("mykey",false,false){
it.currentValue = SPUtils.getInstance().getBoolean(key, it.defalutValue)
}

这样使用一看,发现,我们连最初的currentValue都不用设置了

所以构造参数还能再精简下,让currentValue默认等于defaultValue(这样设置起始没有毛病,因为之后每次都是会走初始化的步骤,从本地存储中读取数据的)

class GlobalDataConfig(
val key: String,
val defaultValue: T,
var currentValue: T = defaultValue,
val initLbd: (GlobalDataConfig) -> Unit
) {
init{
lbd.invoke(this)
} fun setValue(newVal: T) {
currentValue = newVal
updateLocalStorage(currentValue)
} /**
*更新本地存储
*
* @param newVal
*/
private fun updateLocalStorage(value: T) {
if (value is Boolean) {
SPUtils.getInstance().put(key, value)
}
if (value is Float) {
SPUtils.getInstance().put(key, value)
}
if (value is String) {
SPUtils.getInstance().put(key, value)
}
if (value is Int) {
SPUtils.getInstance().put(key, value)
}
if (value is Long) {
SPUtils.getInstance().put(key, value)
}
}
}

然后用起来就变成了这样:

GlobalDataConfig("mykey",false){
it.currentValue = SPUtils.getInstance().getBoolean(key, it.defalutValue)
}

但是,看起来还是有些繁琐,中间初始化的过程能否再优化呢?

刚开始我是没有思路的,因为currentValue在类里面是T类型,而我们通过getBoolean等方法,获得的都是Boolean,String等类型,与T类型不对应,IDE里会提示我们语法不对

然后,突然灵光一闪,我们可以强转类型嘛,如将GlobalDataConfig<T>转为GlobalDataConfig<Boolean>

代码最终即可以改为下面的样子

class GlobalDataConfig<T>(
val key: String,
val defaultValue: T,
var currentValue: T = defaultValue
) {
init {
when{
defaultValue is Boolean -> {
val item = this as GlobalDataConfig<Boolean>
item.setValue(SPUtils.getInstance().getBoolean(key,defaultValue))
}
defaultValue is String -> {
val item = this as GlobalDataConfig<String>
item.setValue(SPUtils.getInstance().getString(key,defaultValue))
}
defaultValue is Int -> {
val item = this as GlobalDataConfig<Int>
item.setValue(SPUtils.getInstance().getInt(key,defaultValue))
}
defaultValue is Double -> {
//SPUtils里面的似乎没有提供获取Double方法...
}
else -> kotlin.error("不支持的数据类型!!目前只支持string,boolean,intdouble四种类型")
}
} /**
* 重置当前值为默认值
*/
fun resetValue() {
setValue(defaultValue)
} /**
* 更改数值
*/
fun setValue(value: T) {
//更新内存的
currentValue = value //更新本地存储的数据
updateLocalStorage(value)
} /**
* 更新本地存储
*/
private fun updateLocalStorage(value: T) {
if (value is Boolean) {
SPUtils.getInstance().put(key, value)
}
if (value is Float) {
SPUtils.getInstance().put(key, value)
}
if (value is String) {
SPUtils.getInstance().put(key, value)
}
if (value is Int) {
SPUtils.getInstance().put(key, value)
}
if (value is Long) {
SPUtils.getInstance().put(key, value)
}
}
}

使用上也很方便:

val openAutoRead =GlobalDataConfig("mykey",true)

使用

稍微补充下使用说明吧

1.新建全局配置类

这里为了方便管理,是建了个Constants常量池

class GlobalData {
companion object {
//是否为VIP(默认不是)
val userStatus = GlobalDataConfig(Constants.SP_USER_STATUS, false)
}
}

2.读取数值

在你需要用的地方,获取数值

val result = GlobalData.userStatus.currentValue

2.更新数值

GlobalData.userStatus.setValue(true)

3.重置数值

GlobalData.userStatus.resetValue()

源码-Android工具类

PS:这里其实还可以做个扩展,比如说加个回调方法列表,每次setValue方法后,执行所有回调方法,实现类似监听数值变动

限于实际情况,我就没有扩展了(各位可以参考下TornadoFx中的GlobalDataConfig的实现)

class GlobalDataConfig<T>(
val key: String,
val defaultValue: T,
var currentValue: T = defaultValue
) {
init {
when{
defaultValue is Boolean -> {
val item = this as GlobalDataConfig<Boolean>
item.setValue(SPUtils.getInstance().getBoolean(key,defaultValue))
}
defaultValue is String -> {
val item = this as GlobalDataConfig<String>
item.setValue(SPUtils.getInstance().getString(key,defaultValue))
}
defaultValue is Int -> {
val item = this as GlobalDataConfig<Int>
item.setValue(SPUtils.getInstance().getInt(key,defaultValue))
}
defaultValue is Double -> {
//SPUtils里面的似乎没有提供获取Double方法...
}
else -> kotlin.error("不支持的数据类型!!目前只支持string,boolean,intdouble四种类型")
}
} /**
* 重置当前值为默认值
*/
fun resetValue() {
setValue(defaultValue)
} /**
* 更改数值
*/
fun setValue(value: T) {
//更新内存的
currentValue = value //更新本地存储的数据
updateLocalStorage(value)
} /**
* 更新本地存储
*/
private fun updateLocalStorage(value: T) {
if (value is Boolean) {
SPUtils.getInstance().put(key, value)
}
if (value is Float) {
SPUtils.getInstance().put(key, value)
}
if (value is String) {
SPUtils.getInstance().put(key, value)
}
if (value is Int) {
SPUtils.getInstance().put(key, value)
}
if (value is Long) {
SPUtils.getInstance().put(key, value)
}
}
}

源码-TornadoFx工具类

TornadoFx这边源码稍微有点多,就不放出来了,详情可以去我的Github库common-controls查阅,里面也含有详细的使用说明(文档的第7节)

TornadoFx这边有些特殊,是结合了JavaFx中提供的可观察对象一起连用,使用上与Android的有所区别

关于TornadoFx和Android的全局配置工具类封装实现及思路解析的更多相关文章

  1. Android实用的Toast工具类封装

    Toast这个提示框大家都晓得,显示一段时间后自动消失,不能获得焦点.但是在使用中有些问题: 1)需要弹出一个新的Toast时,上一个Toast还没有显示完2)可能重复弹出相同的信息3)Toast具体 ...

  2. wemall app商城源码android开发MD5加密工具类

    wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享android开发MD5加密工具类主要代码,供 ...

  3. Android开发调试日志工具类[支持保存到SD卡]

    直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...

  4. Android开源项目大全 - 工具类

    主要包括那些不错的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. 一.依赖注入DI 通过依赖注入减少Vie ...

  5. Android弹出Toast工具类总结

    Android弹出Toast工具类总结,包括系统自带的,也包括自定义的. public class ToastUtil { public ToastUtil() { } public static T ...

  6. Android 中替代 sharedpreferences 工具类的实现

    Android 中替代 sharedpreferences 工具类的实现 背景 想必大家一定用过 sharedpreferences 吧!就我个人而言,特别讨厌每次 put 完数据还要 commit. ...

  7. 获取 Android APP 版本信息工具类(转载)

    获取 Android APP 版本信息工具类 获取手机APP版本信息工具类 1.获取版本名称 2.获取版本号 3.获取App的名称 package com.mingyue.nanshuibeidiao ...

  8. Android 获取手机的厂商、型号、Android系统版本号等工具类(转载)

    Android 获取手机的厂商.型号.Android系统版本号等工具类 1.获取手机制造厂商 2.获取手机型号 3.获取手机系统当前使用的语言 4.获取Android系统版本号 5.获取手机IMEI串 ...

  9. (转载) 百度地图工具类封装(包括定位,附近、城市、范围poi检索,反地理编码)

    目录视图 摘要视图 订阅 赠书 | 异步2周年,技术图书免费选      程序员8月书讯      项目管理+代码托管+文档协作,开发更流畅 百度地图工具类封装(包括定位,附近.城市.范围poi检索, ...

随机推荐

  1. 你可能不知道的 css 内容块

    position 我们都知道元素都拥有 position 这个css属性,先来看看他的基本定义和可用值. 定义 position 决定了元素位置是如何被渲染的 可用值 值 描述 static 默认值, ...

  2. EMS监控用户邮箱

    案例任务:部署日记规则,用户"王淑江"监控用户"王春海"的邮箱. 1.EMS监控用户邮箱 使用PowerShell命令完成任务:使用日记规则部署"王淑 ...

  3. tkinter GUI编程

    tkinter编程概述 tkinter模块包含在Python的基本安装包中.使用tkinter模块编写的GUI程序是跨平台的.可在windows.UNIX.Linux以及Macintonsh OS X ...

  4. Spring原始注解开发-02

    使用@Repository.@Service.@Controller注解配置,使其更加清晰属于哪一层,因为我是模拟的web层,所有没有使用@Controller注解,后面结合web开发会使用到 1.创 ...

  5. 使用IDEA生产JavaDoc文档

    源代码 package com.*****.base; //文档注解 /** * @Author intelliyu * @version 1.0 //版本 * since 1.8 //指明需要最早使 ...

  6. SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(上)

    不断踩坑并解决问题是每个程序员进阶到资深的必要经历并以此获得满足感,而不断阅读开源项目源码和总结思想是每个架构师成长最佳途径.本篇拉开SpringCloud Alibaba最新版本实战和原理序幕,以工 ...

  7. partOne测试收获总结

    测试收获总结   执行类中构造多个方法,将各个功能分解出来,将大的,复杂的问题转化成小的,简单的问题,来进行处理,正所谓复杂问题简单化,简单问题流程化.大道至简编程精益.现总结编程中的一些问题,①在J ...

  8. sqlmap Tamper脚本编写

    sqlmap Tamper脚本编写 前言 sqlmap是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞,目前支持的数据库是MySQL, Oracle, Postg ...

  9. Docker极简入门:使用Docker-Compose 运行网站浏览量统计Demo

    Docker-Compose 是一个可以对 Docker 容器集群的快速编排的工具,能够减轻您心智和手指的负担. 简单的来说 Docker-Compose 就是将你运行多个容器的命令编写到了一起,类似 ...

  10. Docker部署PostgreSQL主从

    #准备 PostgreSQL12.3版本容器两台,部署参考https://www.cnblogs.com/zspwf/p/16113298.html 主库: 192.168.3.14:2200 从库: ...