

关于TornadoFx和Android的全局配置工具类封装实现及思路解析 - Stars-one
source link: https://www.cnblogs.com/stars-one/p/16320957.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关于TornadoFx和Android的全局配置工具类封装实现及思路解析
本文为作者原创,转载请注明出处,谢谢配合
作者:stars-one
链接:https://www.cnblogs.com/stars-one/p/16320957.html
本篇大约有6629个字,阅读预计需要8.29分钟
原文地址: 关于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:
SPUtils
是AndroidUtilCode库的工具类,用于快速设置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的有所区别
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK