During the recent modular refactoring of the project, butterKnife was heavily used in the app module in the previous project, but the migration to the library caused problems because variables in the R class were no longer final, which prompted some thinking
Butterknife’s JakeWharton also provides a solution for R2 (PS: pull request from someone else). The general approach is as follows: use R2 to handle related problems…
@BindView(R2.id.toolbar)
Toolbar toolbar;Copy the code
In the view.getid () method, the value returned is the id of class R, not the ID of R2, and the id of the same variable in the two R classes is not the same, so it will roll over. Example code for the error operation common modification is referenced from the Butter Knife introduction and Usage guide
// This is not the case
@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; }}// A painful fix
@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(a) {
finish();
}Copy the code
But as a programmer, how can you tolerate such a large number of mechanical modifications!!
So the idea is, is there some way that you can create some kind of mapping between R and R2, because they have the same variable name? Then I had a brainwave, a SAO thing in my mind flash and —- “reflection” um… That’s what I’m gonna do with reflection
So, I wrote a utility class, basically, to get the data of R and R2 by reflection, and maintain their variable names and values in two hashmaps. Then, I can bridge the variable names between R and R2, and realize that the same variable int is worth converting
The core code is to get the relevant variable names and values through reflection and store them in a 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(); }}}}Copy the code
Other code for initializing maps is easy to understand, and the reason is quite simple. For reflection, it is found that the second reflection for the same class is significantly faster than the first reflection. Welcome to comment :smile), for the variable should be set to static, because considering static memory is application shared, afraid of affecting other modules, not set, as for other optimizations, can be modified for your own project.
Screenshots from the test:
// Test the code
// The triggered button is bt_home_1
RCaster caster = new RCaster(R.class,R2.class);
Logger.d(caster.cast(view.getId()));Copy the code
Attach the complete code for the utility class
package com.company;
import java.lang.reflect.Field;
import java.util.HashMap;
/** * Created by retrox on 23/03/2017. */
public class RCaster {
//id gets the attribute name
private HashMap<Integer, String> r1Map = new HashMap<>();
// Attribute name retrieves 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;
}
/** * Initializes r1Map */
@SuppressWarnings("Duplicates")
private void initMap1(a) {
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");
}
/** * Initializes r2Map */
@SuppressWarnings("Duplicates")
private void initMap2(a) {
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"); }}Copy the code
Enjoy ! If you think it’s helpful, you can like it or transfer it to someone else