保存应用的一些配置信息是很常用的功能。
SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,好用且强大,但是某些情况下不是很好用。
比如只支持JAVA基本数据类型,不支持自定义的数据类型。以XML文件的形式保存在 /data/data/PACKAGE_NAME/shared_prefs目录下,应用一旦卸载就跟着卸载了,没法保留配置或者把配置文件拷贝出来。(这在一些智能终端设备上保留配置信息和能够拷贝出来是常用的功能需求。)
虽然改变存储位置为其他目录,可以通过反射的方式实现,但是感觉还是不够简单。
之前有对SharedPreferences的一个操作封装,参见:https://blog.csdn.net/yyz_1987/article/details/104122764
所以,这里以json序列化存储文件的方式简单实现了一个,使用也更简单。
github地址;https://github.com/yangyongzhen/configer.git
举例,想保存个服务的IP和端口信息,使用如下:
SysCfg sysCfg = SysCfg.getInstance(); sysCfg.setIP("127.0.0.1"); sysCfg.setPort(5050); sysCfg.save()
就这么简单,你已经完成了IP和Port的参数配置,sysCfg 是全局的一个系统参数配置类。(save操作会在内部存储为了一个名称为SysCfg的json文件)。
只需要应用启动时,如下调用,即完成的加载参数从文件到sysCfg反序列化过程:
SysCfg sysCfg = SysCfg.getInstance(); //从文件中加载json配置信息到sysCfg sysCfg.load();
够简单吧,即使完全不了解SharedPreferences的人也能照葫芦画瓢的顺溜的使用。
比起操作SharedPreferences和sqllite的方式简单多了,而且可以更改存储位置和拷贝出配置文件。
SysCfg 配置文件类里,可以支持定义任何自定义类型,只要它能正常序列化为json都可以存储。
并不是你的配置文件类必须为SysCfg,这里仅是举例。定义成任意名称都可,只需集成自我封装的Configer基础类即可。
How to use?
Add it in your root build.gradle at the end of repositories: allprojects { repositories { ... maven { url 'https://jitpack.io' } } } Step 2. Add the dependency dependencies { implementation 'com.github.yangyongzhen:configer:v1.0' }
完整示例如下:
package com.yangyongzhen.demo; import com.yangyongzhen.configer.Configer; import com.yangyongzhen.configer.Ignore; /** SysCfg 系统配置类 */ public class SysCfg extends Configer { //Ignore,不序列化存储的使用Ignore注解 @Ignore public static final String TAG = SysCfg.class.getSimpleName(); //做为配置文件的默认文件名 @Ignore private static SysCfg _instance = null; private Integer Ver = 0; //版本号 private String Time =""; //时间 private String PosCode = ""; //终端编号 private String UserName = ""; //登录用户名 private String UserPwd = ""; //密码 public SysCfg() { super(TAG); } private SysCfg(String filename) { super(filename); } public Integer getVer() { return Ver; } public void setVer(Integer ver) { Ver = ver; } public String getTime() { return Time; } public void setTime(String time) { Time = time; } public String getPosCode() { return PosCode; } public void setPosCode(String posCode) { PosCode = posCode; } public String getUserName() { return UserName; } public void setUserName(String userName) { UserName = userName; } public String getUserPwd() { return UserPwd; } public void setUserPwd(String userPwd) { UserPwd = userPwd; } @Override public String toString() { return "SysCfg{" + "Ver=" + Ver + ", Time='" + Time + '\'' + ", PosCode='" + PosCode + '\'' + ", UserName='" + UserName + '\'' + ", UserPwd='" + UserPwd + '\'' + '}'; } public static SysCfg getInstance() { if (_instance == null) { synchronized(SysCfg.class){ if (_instance == null) { _instance = new SysCfg(TAG); } } } return _instance; } }
package com.yangyongzhen.demo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import com.yangyongzhen.configer.Configer; public class MainActivity extends AppCompatActivity { private final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //更改存储目录为mydir,默认为/Android/data Configer.setDirPath("/mydir"); SysCfg config = SysCfg.getInstance(); //加载 config.load(); Log.d(TAG,config.toString()); //赋值 config.setVer(500); config.setUserName("yangyongzhen"); //存储 config.save(); //再次读取测试 SysCfg config1 = SysCfg.getInstance(); config1.load(); Log.d(TAG,config1.toString()); } }
贴一下基类的实现:
package com.yangyongzhen.configer; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.yangyongzhen.configer.utils.FileUtil; import com.yangyongzhen.configer.utils.GsonUtil; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Configer{ private static final String TAG = "Configer"; private static String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath(); private static String dirPath = "/Android/data"; private transient String filename; public Configer(String filename) { this.filename = filename; } public Boolean save(){ //Log.d(TAG,this.toString()); String jsStr = GsonUtil.GsonString(this); //Log.d(TAG,jsStr); Boolean ret = FileUtil.writeFile(rootPath+dirPath,filename,jsStr); return ret; } public Boolean load(){ Class<?> cls = this.getClass(); Object rec = null; String strfile = FileUtil.readFile(rootPath+dirPath+"/"+filename,""); if (!TextUtils.isEmpty(strfile)) { JSONObject jsonObject = JSON.parseObject(strfile); rec = GsonUtil.deserializer(jsonObject, this.getClass()); Log.d(TAG,rec.toString()); } if(rec != null){ Class<?> cls1 = rec.getClass(); Field[] declaredFields = cls.getDeclaredFields(); for (int i = 0; i < declaredFields.length; i++) { Field field = declaredFields[i]; if (field.isAnnotationPresent(Ignore.class)) { continue; } try { Method method = cls1.getDeclaredMethod("get"+upperHeadChar(field.getName())); Object obj = method.invoke(rec); field.setAccessible(true); field.set(this,obj); } catch (Exception e) { Log.d(TAG,e.toString()); //e.printStackTrace(); return false; } } return true; } return false; } /** * 首字母大写,in:deleteDate,out:DeleteDate */ public static String upperHeadChar(String in) { String head = in.substring(0, 1); String out = head.toUpperCase() + in.substring(1, in.length()); return out; } public static String getRootPath() { return rootPath; } public static void setRootPath(String rootPath) { Configer.rootPath = rootPath; } public static String getDirPath() { return dirPath; } public static void setDirPath(String dirPath) { Configer.dirPath = dirPath; } }