过时: butterknife现在的plugin已处理id不一致的问题
至于R2是什么东西 -> 异步butterknife官方Github主页文档
最近在模块化重构项目的时候,之前的项目在app模块里大量使用了butterknife,但是迁移到library里面后由于R类中变量不再是final类型而导致各种问题,于是引发了一些思考
Butterknife 的作者JakeWharton大神也提供了R2的解决方案(PS:别人给他的pull request),大致的使用方法如下 ,使用R2处理相关问题...
@BindView(R2.id.toolbar)
Toolbar toolbar;
那么问题来了,就是在 view.getId()
方法中,系统返回的值是R类中的id而不是R2中的id,而且两个R类中相同变量的id并不相同,所以会翻车。错误操作普通修改方式的实例代码引用自博客Butter Knife简介和使用指南
// 错误的写法
@OnClick({R2.id.back, R2.id.txt_bind_we_chat_btn, R2.id.txt_bind_phone_btn})
public void onClick(View view) {
switch (view.getId()) {
case R2.id.back:
break;
case R2.id.txt_bind_phone_btn:
break;
case R2.id.txt_bind_we_chat_btn:
break;
}
}
// 一个很蛋疼的修复处理方式
@OnClick(R2.id.txt_bind_we_chat_btn)
public void onBindWeChatClick(View v) {
bindWeChat();
}
@OnClick(R2.id.txt_bind_phone_btn)
public void onBIndPhoneClick(View v) {
bindPhoe();
}
@OnClick(R2.id.back)
public void onBackClick() {
finish();
}
但是作为一个程序员,怎么能够忍受这种大量的机械修改!!
我的思路就是:是不是可以通过某种方式,对R类和R2类建立起某种映射关系,因为他们的变量名字是相同的。然后我灵机一动,一个骚东西在脑海一闪而过 ---- "反射”
嗯... 我就是要用反射这种骚东西
于是,我写了一个工具类,大体就是,通过反射获取R类和R2类的数据,将他们的变量名字和值建立在两个HashMap里面维护,然后就可以通过变量名搭桥,实现R,R2之间相同变量int值得转化
核心代码就在于,通过反射获取相关变量名和变量值然后存储在HashMap里面
for (Class aClass : classes) {
// System.out.println(aClass.getSimpleName());
if (aClass.getSimpleName().equals("id")) {
Field[] fields = aClass.getFields();
for (Field field : fields) {
field.setAccessible(true);
try {
int x = (int) field.get(r);
// System.out.println(field.getName() + " ----> " + x);
r1Map.put(x, field.getName());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
其他的初始化map之类代码都很容易懂,道理也是蛮简单的,对于反射,经过计时的测试,发现对于相同的class,第二次反射的速度要大幅度快于第一次(推测,JVM对于反射可能是有缓存机制,如果大家有证实或者科学解释,欢迎在评论区发表见解 :smile),对于变量是不是要设置成静态,因为考虑到static内存是application共享,怕影响其他模块就没有设置,至于其他的优化,可以针对自己的项目进行修改.
测试时候的截图 :
//测试代码
// 触发的按钮是 bt_home_1
RCaster caster = new RCaster(R.class,R2.class);
Logger.d(caster.cast(view.getId()));
附上工具类的完整代码
package com.company;
import java.lang.reflect.Field;
import java.util.HashMap;
/**
* Created by retrox on 23/03/2017.
*/
public class RCaster {
//id取得属性名字
private HashMap<Integer, String> r1Map = new HashMap<>();
//属性名字回取id
private HashMap<String, Integer> r2Map = new HashMap<>();
private Class R;
private Class R2;
public RCaster(Class r, Class r2) {
R = r;
R2 = r2;
initMap1();
initMap2();
}
/**
* R1 id cast to R2
*
* @param rid
* @return
*/
public int cast(int rid) {
String name = r1Map.get(rid);
int id2 = r2Map.get(name);
return id2;
}
/**
* 初始化r1Map
*/
@SuppressWarnings("Duplicates")
private void initMap1() {
long time = System.currentTimeMillis();
Class[] classes = R.getClasses();
Object r = null;
try {
r = R.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
for (Class aClass : classes) {
// System.out.println(aClass.getSimpleName());
if (aClass.getSimpleName().equals("id")) {
Field[] fields = aClass.getFields();
for (Field field : fields) {
field.setAccessible(true);
try {
int x = (int) field.get(r);
// System.out.println(field.getName() + " ----> " + x);
r1Map.put(x, field.getName());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
long time2 = System.currentTimeMillis();
long timeCost = time2 - time;
System.out.println("\nTimecost:" + timeCost + "ms");
}
/**
* 初始化r2Map
*/
@SuppressWarnings("Duplicates")
private void initMap2() {
long time = System.currentTimeMillis();
Class[] classes = R2.getClasses();
Object r = null;
try {
r = R2.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
for (Class aClass : classes) {
if (aClass.getSimpleName().equals("id")) {
Field[] fields = aClass.getFields();
for (Field field : fields) {
field.setAccessible(true);
try {
int x = (int) field.get(r);
// System.out.println(field.getName() + " ----> " + x);
// r2Map.put(x, field.getName());
r2Map.put(field.getName(),x);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
long time2 = System.currentTimeMillis();
long timeCost = time2 - time;
System.out.println("\nTimecost:" + timeCost + "ms");
}
}
Enjoy !
觉得有帮助可以点个喜欢也可以转给别人看哦