Android拼接实现动态对象方法详解

作者:流浪汉kylin 时间:2021-12-23 10:09:46 

1. 前言

我们往往有些配置文件,当项目大的时候,一些配置文件或者一些判断逻辑就会变得复杂,会出现很多判断语句,我在想,能不能通过前缀拼接动态参数并且借助反射等方式去消除一些判断,让这些判断的地方去实现动态。

当前只是有个想法,但是这个操作又没有风险,对性能影响大不大,会不会在使用中出现什么问题,还不得而知,下面就用一些Demo来描述一下这个方案。

这个思路的规则就是:默认前缀拼接动态参数获取对象,动态参数可以是从后台获取,可以是用文件中获取,可以是从系统参数获取,等等,任何你能想到的地方,这个根据自己的场景去涉及从何获取。

2. 动态选密钥

举例的场景不一定好,但是应该能看出这个方案的使用方式。

假如我们有做跨端的对称加密,然后希望密钥有几套,不固定只有一套,然后要动态去选择密钥,当然这个动态的条件要简单,不然也只能if-else去写了。假如我有10套密钥,我根据当前的时间戳的最后一位,去选择使用哪套

假设这些公钥

public class KeyLibs {
   public static final String KEY0 = "0000000000000000";
   public static final String KEY1 = "1111111111111111";
   public static final String KEY2 = "2222222222222222";
   public static final String KEY3 = "3333333333333333";
   public static final String KEY4 = "4444444444444444";
   public static final String KEY5 = "5555555555555555";
   public static final String KEY6 = "6666666666666666";
   public static final String KEY7 = "7777777777777777";
   public static final String KEY8 = "8888888888888888";
   public static final String KEY9 = "9999999999999999";
}

如果我要用if-else去写

String key;
int type = (int) ((System.currentTimeMillis()/1000) % 10);
if (type == 0){
   key =  KeyLibs.KEY0;
}else if (){......}
......
else if (type == 9){
   key =  KeyLibs.KEY9;
}

这样写就很让人不舒服,但是如果我们用反射

try {
   long time = System.currentTimeMillis()/1000;
   Log.v("mmp", "获取到的时间:" + time);
   Class cls = Class.forName("com.kylin.demo.KeyLibs");
   Field fields = cls.getDeclaredField("KEY" + (time % 10));
   fields.setAccessible(true);
   String result = (String) fields.get(null);
   Log.v("mmp", "获取到的key:" + result);
} catch (Exception e) {
   e.printStackTrace();
}

可以看看结果

Android拼接实现动态对象方法详解

这里的"KEY" + (time % 10)就是拼接操作

这样据这个例子好像又感觉不要太好,在这个基础上我们变一变。假如我们有很多套域名,根据一个参数的值去判断去用什么域名。

根据一个参数的值去判断去用什么域名,这个参数可以是后台返回一个string字符串,可以是写在文件中(比如利用v1签名的漏洞的参数),也可以是其它方式。总之需要只根据这个参数的值去判断使用哪个域名 ,那我们可以这样做

先写下域名常量

public class KeyLibs {
   public static final String URL_SHUAI = "www.shuai.com";
   public static final String URL_ZHENDESHUAI = "www.zhendeshuai.com";
   public static final String URL_SHIFENSHUAI = "www.shifenshuai.com";
   public static final String URL_QUESHISHUAI = "www.queshishuai.com";
}

然后通过反射去获取

try {
   String type = .......
   Class cls = Class.forName("com.kylin.demo.KeyLibs");
   // toUpperCase 是转大写
   Field fields = cls.getDeclaredField("URL_" + toUpperCase(type));
   fields.setAccessible(true);
   String result = (String) fields.get(null);
} catch (Exception e) {
   e.printStackTrace();
}

假如你的type拿到的是shifenshuai,那这里拿到的域名就是URL_SHIFENSHUAI。那有个朋友就说了,为什么不动态返回这个域名呢,我这不是举例嘛,没想到什么比较好的例子,大概能看懂这个意思就行。

这里的"URL_" + toUpperCase(type)就是拼接操作

3. 换肤上的使用

假如我要使用换肤,我可以这样定规则:我的皮肤资源ID的名称是原资源的名称加上下划线加上皮肤名

比如我的这一套皮肤的皮肤名是"plugin",我的原皮肤中有个图片kylin_close,那我的这个图片在这套皮肤中的名字就叫kylin_close_plugin

Android拼接实现动态对象方法详解

PS:我这里只是举个例子,一般皮肤资源不会直接这样和原资源放在一起,要么动态皮肤放在插件中,要么静态皮肤放在单独一个文件用gradle去控制资源合并

那我要做的就是当我从任何地方接收到这个皮肤名之后,我把原皮肤换成新的皮肤。Resources的getIdentifier能根据名称找到皮肤,但我不想通过名称,我想通过资源,这样也方便我查看资源,那我可以这样写 (代码直接在这写,没经过验证,如果拿去用有问题,可自行调整)

public int getPluginId(int id){
   String name = "plugin"; // todo 动态获取的参数
   String rName = getResources().getResourceName(id);
   rName = rName + "_" + name;
   // todo 这里我写死是drawable,显示可以根据TypeId去判断是什么
   int result = getResources().getIdentifier(rName, "drawable", getPackageName());;
   if (result == -1){
       result = id; //找不到资源的情况下用会原资源
   }
   return result;
}

在调用的地方

imageView.setImageResource(getPluginId(R.drawable.kylin_close));

这里的rName = rName + "_" + name就是拼接操作。

先解读一下这段代码,因为也算是不完整的代码。name就是我们获取的动态参数,上面也说了,这个参数是可以从后台反,可以从本地文件拿,可以从你自己设计的任何一个地方拿到。然后getResources().getResourceName就是根据传进来的资源ID拿到资源名称,然后rName = rName + "_" + name拼接操作,就是得到我们皮肤的资源名称,再用getIdentifier方法通过资源名称拿到资源ID,最后判断如果拿不到资源ID的话,就返回原资源ID。 然后这里有个地方我没写,就是你可以通过资源ID去判断资源的类型(我这里写死drawable),其实这个可以根据id去判断,我们都知道ID的组成是有规则的,分为PackageId、TypeId、EntryId这些,我们可以进行拆解判断TypeId就知道是什么资源了,这里我就不演示了,相信大家能理解。

好,那这么做的好处是什么,这么做其实有个好处就是如果你的某个资源要新皮肤,你直接给新皮肤的资源按约定格式去命名就行,这样就不用去改代码。

4. 总结

我这里其实感觉例子列举得不是很好,但是主要是想表达,通过自己去约定一套规则,通过前缀拼接动态参数的方式去消除一些非必要的判断语句,并且在一定程度上能提高扩展性。但相对的也有缺点,比如换肤那个例子,我先通过ID拿到名称,再通过名称拿到目标ID,就其实多走了两步,但是这个对性能的影响有多少,这就需要具体去取舍了。因为我是一想到就写出来,所以可能有些地方没考虑周全。

来源:https://juejin.cn/post/7203648441720717372

标签:Android,拼接,动态对象
0
投稿

猜你喜欢

  • Java多线程状态及方法实例解析

    2021-09-10 22:49:53
  • Android7.0自动更新适配 包解析异常

    2022-02-13 11:21:00
  • C#强制转换和尝试转换的方法

    2021-10-10 10:48:23
  • Java微信跳一跳操作指南

    2022-07-06 11:14:36
  • JavaGUI常用三种布局使用介绍

    2023-05-19 08:01:06
  • Mybatis自关联查询一对多查询的实现示例

    2021-08-21 04:06:16
  • 详解Android中PopupWindow在7.0后适配的解决

    2022-12-07 11:16:59
  • Java通过底层原码了解数组拷贝

    2021-10-07 12:47:47
  • Java实战之酒店人事管理系统的实现

    2021-06-02 16:44:37
  • java、android可用的rtp封包解包h264案例

    2021-11-27 01:53:18
  • 完美解决Spring Boot前端的Access-Control-Allow-Origin跨域问题

    2023-09-19 10:16:28
  • c# 单例模式的实现

    2023-06-12 01:16:44
  • C#使用CefSharp实现内嵌网页详解

    2022-04-12 15:02:00
  • SpringBoot2整合Ehcache组件实现轻量级缓存管理

    2022-06-18 18:11:16
  • Android短信验证码(用的Mob短信验证)

    2022-12-16 15:22:41
  • Android TV 3D卡片无限循环效果

    2022-03-26 04:06:48
  • spring mvc中@RequestBody注解的作用说明

    2022-04-07 14:15:02
  • 使用Spring Cloud Feign上传文件的示例

    2021-08-25 04:37:38
  • 各种格式的编码解码工具类分享(hex解码 base64编码)

    2021-11-17 07:04:51
  • Springboot整合PageOffice 实现word在线编辑保存功能

    2022-12-03 22:38:18
  • asp之家 软件编程 m.aspxhome.com