敞开成长之旅!这是我参加「日新计划 2 月更文应战」的第 14 天,点击检查活动详情
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();
}
能够看看成果
这儿的”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
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,就其实多走了两步,可是这个对功能的影响有多少,这就需求具体去取舍了。由于我是一想到就写出来,所以可能有些当地没考虑周全。