Android配置文件操作模块封装,全互联网最简单好用的封装

简介: Android配置文件操作模块封装,全互联网最简单好用的封装

Android中虽然提供了SharedPreference类方便的对配置文件进行操作。但是好用吗?


假如有成百上千的参数需要存储,这样一个个分散的写法累死个人啊。本来几分钟能搞定的活,你可能得几个钟头。效率能是一个等级?且到处分散的写法,也容易让人看晕,给维护造成困难。


先来看结果:


原来的使用方式是这样的:


SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
//读取存储的IP和端口
String ip  = sp.getInt("IP", "127.0.0.1");
int port = sp.getString("PORT",5050);
//保存IP和端口
ip = "218.28.111.121";
sp.putString("IP",ip)


如果参数少还无所谓,如果需要用到的参数很多,且到处都是。这种用法岂不是太混乱,太繁琐?


来看看原来的这种有多恐怖,



再来出一道题,假如我有一套票价参数要存储,每种卡类型有卡类型,折扣,提示信息等参数需要存储。让你用SharedPreferences去存储,你会怎么做?


先看下c语言里结构体票价参数的定义,让用Android的SharedPreferences怎么办?


即便不使用SharedPreferences,使用文件的方式存为json或xml或ini或yaml,哪个都不是那么简单好用。




如果参数很多,累死个人了,很容易漏了或忘了赋值导致参数没存储。且没有全局管理意识的人会到处使用。导致你甚至不知道到底存储了哪些东东,哪些是存储了,哪些是没存储的。只能费劲儿的找,搜索,CTRL+F...


再来看看这种方式:


 syscfg.ip = "218.28.133.181";
 syscfg.port = 22288;
 syscfg.saveCfg();
 Log.d(TAG,syscfg.toString());
 dealCfg.ver = 12;
 dealCfg.time = "201910251551";
 dealCfg.discInfo[0].cardType = 5;
 dealCfg.discInfo[0].purseDisc = 100;
 dealCfg.discInfo[1].cardType = 6;
 dealCfg.discInfo[1].purseDisc = 200;
 dealCfg.saveCfg();


可以看到实现后使用是多么的简单直观。开机后先load一次从配置文件加载到成员变量中。


后续随便使用和赋值。想要保存,直接调用save()即可。且跟配置相关的参数都在全局的一个SysCfg中,


还害怕漏了或找不到吗?按这样封装好后,即便不会Android存储的人,也会清爽使用。


//跟系统参数相关的所有参数配置和存储
Class SysCfg{
   String ip;
   int port;
   void load(){
    ...
   }
   void save(){
   //自动把ip,port的内容存储起来
   for(...){
     put("ip",value)
     ...
   }
  static void main(String[] args){
     SysCfg cfg = new SysCfg();
     cfg.load()//加载配置文件中的参数到成员变量中
     cfg.ip = "127.0.0.1"; //赋值
     cfg.port= 5050;
     cfg.save();//自动持久化存储了SysCfg的所有参数
  }
}


最后,封装实现的代码分享一下,使用注解+反射让配置文件操作如此清晰和简单。


所有需要用到的参数,定义在一个继承自Configer的类中即可。


package com.newcapec.b601.config;
import android.content.Context;
import java.lang.reflect.Field;
/**
 * Android存储的封装
 * Author:yangyongzhen
 * QQ:534117529
 */
public class Configer {
    public static final String TAG = "Configer"; //做为配置文件的文件名
    private SharedPreferencesHelper helper;
    //===========================================================
    public Configer(Context cx,String name){
        helper = new SharedPreferencesHelper(cx,name);
    }
    /**
     * 自动完成所有带有Save注解的成员变量的存储
     */
    public int saveCfg(){
        Class cls = this.getClass();
        Field[] fields = cls.getDeclaredFields();
        for(Field field :fields) {
            if (field.isAnnotationPresent(Save.class)) {
                try {
                    Save sa = (Save) field.getAnnotation(Save.class);
                    String key = sa.value();
                    String val = (String) helper.get(key,"");
                    Object obj = field.get(this);
                    if(obj.equals(val)){
                        continue;
                    }
                    if(obj instanceof String) {
                        helper.put(key,obj);
                    }else if(obj instanceof Integer){
                        helper.put(key,obj);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    return 1;
                }
            }
        }
        return 0;
    }
    /**
     * 自动完成所有带有Save注解的成员变量的加载
     * @return
     */
    public int openCfg(){
        Class cls = this.getClass();
        Field[] fields = cls.getDeclaredFields();
        for(Field field :fields) {
            if (field.isAnnotationPresent(Save.class)) {
                try {
                    Save sa = (Save) field.getAnnotation(Save.class);
                    String key = sa.value();
                    if(field.get(this) instanceof String) {
                        String val = (String) helper.get(key,"");
                        field.set(this,val);
                    }else if(field.get(this) instanceof Integer){
                        Integer val = (Integer) helper.get(key,0);
                        field.set(this,val);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    return 1;
                }
            }
        }
        return 0;
    }
}


Save的注解也很简单:


package com.newcapec.testsqllite.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Save {
    String value();
}


使用方式:


package com.newcapec.b601.config;
import android.content.Context;
public class SysCfg extends Configer {
    public static final String TAG = "SysCfg"; //做为配置文件的文件名
    private static SysCfg _instance = null;
    private SysCfg(Context cx,String name) {
        super(cx,name);
    }
    //========================================================
    //IP地址
    //(需要持久化存储的,加上Save注解即可)
    @Save("ip")
    public String ip = "127.0.0.1";
    //服务器端口
    @Save("port")
    public Integer port = 999;
    public Integer port1 = 1000;
    @Override
    public String toString() {
        return "Sys{" +
                "ip='" + ip + '\'' +
                ", port=" + port +
                ", port1=" + port1 +
                '}';
    }
    public static SysCfg getInstance(Context context) {
        if (_instance == null) {
            synchronized(SysCfg.class){
                if (_instance == null) {
                    _instance = new SysCfg(context,TAG);
                }
            }
        }
        return _instance;
    }
}


 syscfg.ip = "218.28.133.181";
 syscfg.port = 22288;
 syscfg.saveCfg();
 Log.d(TAG,syscfg.toString());
 dealCfg.ver = 12;
 dealCfg.time = "201910251551";
 dealCfg.discInfo[0].cardType = 5;
 dealCfg.discInfo[0].purseDisc = 100;
 dealCfg.discInfo[1].cardType = 6;
 dealCfg.discInfo[1].purseDisc = 200;
 dealCfg.saveCfg();
相关文章
|
3月前
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用
|
3月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
3月前
|
监控 Java 开发工具
如何快速对接Android平台GB28181接入模块(SmartGBD)
大牛直播SDK推出的Android平台GB28181接入SDK(SmartGBD),可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景,可能是业内为数不多功能齐全性能优异的商业级水准GB28181接入SDK。
|
3月前
|
Android开发 iOS开发
Android项目架构设计问题之将隐式跳转的逻辑进行抽象和封装如何解决
Android项目架构设计问题之将隐式跳转的逻辑进行抽象和封装如何解决
41 0
|
3月前
|
编解码 开发工具 Android开发
Android平台RTMP直播推送模块技术接入说明
大牛直播SDK跨平台RTMP直播推送模块,始于2015年,支持Windows、Linux(x64_64架构|aarch64)、Android、iOS平台,支持采集推送摄像头、屏幕、麦克风、扬声器、编码前、编码后数据对接,功能强大,性能优异,配合大牛直播SDK的SmartPlayer播放器,轻松实现毫秒级的延迟体验,满足大多数行业的使用场景。RTMP直播推送模块数据源,支持编码前、编码后数据对接
|
3月前
|
监控 开发工具 Android开发
结合GB/T28181规范探讨Android平台设备接入模块心跳实现
本文介绍了GB28181标准中的状态信息报送机制,即心跳机制,用于监控设备与服务器间的连接状态。根据国标GB/T28181-2016,设备在异常时需立即发送状态信息,在正常状态下则按固定间隔(默认60秒)定期发送。若连续三次(默认值)未收到心跳,则视为离线。文章展示了在Android平台的GB28181设备接入模块(SmartGBD)中,如何调整心跳间隔为20秒及超时次数为3次,并给出了心跳消息的示例和异常处理代码片段。对于希望深入了解或遇到问题的开发者,作者提供了进一步交流的机会。
|
3月前
|
编解码 API 开发工具
Android平台轻量级RTSP服务模块二次封装版调用说明
本文介绍了Android平台上轻量级RTSP服务模块的二次封装实践,旨在简化开发流程,让开发者能更专注于业务逻辑。通过`LibPublisherWrapper`类提供的API,可在应用中轻松初始化RTSP服务、配置视频参数(如分辨率、编码类型)、启动与停止RTSP服务及流发布,并获取RTSP会话数量。此外,还展示了如何处理音频和视频数据的采集与推送。最后,文章提供了从启动服务到销毁资源的完整示例,帮助开发者快速集成实时流媒体功能。
|
3月前
|
编解码 开发工具 Android开发
Android平台轻量级RTSP服务模块技术接入说明
为满足内网无纸化/电子教室等内网超低延迟需求,避免让用户配置单独的服务器,大牛直播SDK在推送端发布了轻量级RTSP服务SDK。 轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务,实现本地的音视频数据(如摄像头、麦克风),编码后,汇聚到内置RTSP服务,对外提供可供拉流的RTSP URL,轻量级RTSP服务,适用于内网环境下,对并发要求不高的场景,支持H.264/H.265,支持RTSP鉴权、单播、组播模式,考虑到单个服务承载能力,我们支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。
|
4月前
|
Android开发
Android kernel 操作gpio
Android kernel 操作gpio
42 0
|
5月前
|
存储 算法 Java
Android 进阶——代码插桩必知必会&ASM7字节码操作
Android 进阶——代码插桩必知必会&ASM7字节码操作
241 0