关于TornadoFx和Android的全局配置工具类封装实现及思路解析
原文地址: 关于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的有所区别
关于TornadoFx和Android的全局配置工具类封装实现及思路解析的更多相关文章
- Android实用的Toast工具类封装
Toast这个提示框大家都晓得,显示一段时间后自动消失,不能获得焦点.但是在使用中有些问题: 1)需要弹出一个新的Toast时,上一个Toast还没有显示完2)可能重复弹出相同的信息3)Toast具体 ...
- wemall app商城源码android开发MD5加密工具类
wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享android开发MD5加密工具类主要代码,供 ...
- Android开发调试日志工具类[支持保存到SD卡]
直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...
- Android开源项目大全 - 工具类
主要包括那些不错的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. 一.依赖注入DI 通过依赖注入减少Vie ...
- Android弹出Toast工具类总结
Android弹出Toast工具类总结,包括系统自带的,也包括自定义的. public class ToastUtil { public ToastUtil() { } public static T ...
- Android 中替代 sharedpreferences 工具类的实现
Android 中替代 sharedpreferences 工具类的实现 背景 想必大家一定用过 sharedpreferences 吧!就我个人而言,特别讨厌每次 put 完数据还要 commit. ...
- 获取 Android APP 版本信息工具类(转载)
获取 Android APP 版本信息工具类 获取手机APP版本信息工具类 1.获取版本名称 2.获取版本号 3.获取App的名称 package com.mingyue.nanshuibeidiao ...
- Android 获取手机的厂商、型号、Android系统版本号等工具类(转载)
Android 获取手机的厂商.型号.Android系统版本号等工具类 1.获取手机制造厂商 2.获取手机型号 3.获取手机系统当前使用的语言 4.获取Android系统版本号 5.获取手机IMEI串 ...
- (转载) 百度地图工具类封装(包括定位,附近、城市、范围poi检索,反地理编码)
目录视图 摘要视图 订阅 赠书 | 异步2周年,技术图书免费选 程序员8月书讯 项目管理+代码托管+文档协作,开发更流畅 百度地图工具类封装(包括定位,附近.城市.范围poi检索, ...
随机推荐
- win10 Celery异步任务报错: Task handler raised error: ValueError('not enough values to unpack (expected 3, got 0)
示例代码如下: from celery import Celery app = Celery('tasks', backend='redis://×××:6379/1', broker='redis: ...
- MongoDB从bson文件中恢复数据
首先需要到mangodb的安装目录的bin下面找到mongorestore.exe WIN10系统MongoDB安装目录bin文件夹下没有mongorestore.exe 先下载工具 https:/ ...
- java中请给出例子程序:找出两个数的最大公约数和最小公倍数
9.2 找出12和8的最大公约数和最小公倍数. public class Test { public static void main(String[] args) { ...
- uni-app中 未收藏和已收藏功能展示
效果图如下: 未收藏: 已收藏: 代码实现: 1 <view class="jichu"> 2 <view class="name">x ...
- string 函数
传送门:https://www.w3school.com.cn/php/php_ref_array.asp addcslashes() 返回在指定的字符前添加反斜杠的字符串. addslashes() ...
- 控制反转 IOC 理论推导
控制反转 IOC 理论推导 按照我们传统的开发,我们会先去 dao 层创建一个接口,在接口中定义方法. public interface UserDao { void getUser(); } 然后再 ...
- Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?
原始数据存储在 DB 中(如 MySQL.Hbase 等),但 DB 的读写性能低.延迟高. 比如 MySQL 在 4 核 8G 上的 TPS = 5000,QPS = 10000 左右,读写平均耗时 ...
- eNSP路由器启动#号问题排查
1.删除拖出来的设备,重新拖出来一台---我用过[有时候好使] 2.确保Ensp的设置-工具-Virtual Box安装目录是否正确--我也遇到过[尤其是卸载掉Virtual Box重装之后] 3.确 ...
- python基础练习题(题目 打印出杨辉三角形前十行。)
day38 --------------------------------------------------------------- 实例061:杨辉三角 题目 打印出杨辉三角形前十行. 分析: ...
- Django学习——路由层之路由匹配、无名分组、有名分组、反向解析
路由层之路由匹配 """路由你可以看成就是出去ip和port之后的地址""" url()方法 1.第一个参数其实是一个正则表达式 2.一旦第 ...