In XposedBridge source ( https://github.com/rovo89/XposedBridge), the method of the reflected field `de.robv.android.xposed.XposedHelpers` encapsulated inside the class. Xposed below to see how to get and set fields are worth it
Gets the value of the field
Gets the field values are many methods, there are ways to obtain basic type field value (getIntField, getLongField, getDoubleField ...), there are ways to get the value of the object type field. They achieve the same. We get the object type field value, for example, to analyze how the reflection values acquired Xposed field objects. this feature of the class getObjectField method XposedHelpers
public static Object getObjectField(Object obj, String fieldName) {
try {
return findField(obj.getClass(), fieldName).get(obj);
} catch (IllegalAccessException e) {
// should not happen
XposedBridge.log(e);
throw new IllegalAccessError(e.getMessage());
} catch (IllegalArgumentException e) {
throw e;
}
}
getObjectField
There are two parameters: the object belongs to a field is to be obtained, the other is the name of the field.
getObjectField
The main call findField
method and call findField
set methods return the object to see findField method:
public static Field findField(Class<?> clazz, String fieldName) {
String fullFieldName = clazz.getName() + '#' + fieldName;
if (fieldCache.containsKey(fullFieldName)) {
Field field = fieldCache.get(fullFieldName);
if (field == null)
throw new NoSuchFieldError(fullFieldName);
return field;
}
try {
Field field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException e) {
fieldCache.put(fullFieldName, null);
throw new NoSuchFieldError(fullFieldName);
}
}
findField
Start method, first stitching a full field name. Then determine whether there is a cache in this field based on the full field names, if you remove the field from the cache, you do not look at, so the child can do to improve the reflection rate. If you find out from the cache before a null value, on behalf of this field too, I can not find, and throw an exception.
Cache name fieldCache
, it is a HashMap.
private static final HashMap<String, Field> fieldCache = new HashMap<>();
If the cache does not have this field, call the findFieldRecursiveImpl
Find field:
private static Field findFieldRecursiveImpl(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
while (true) {
clazz = clazz.getSuperclass();
if (clazz == null || clazz.equals(Object.class))
break;
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException ignored) {}
}
throw e;
}
}
findFieldRecursiveImpl
Firstly, look at the Class class that comes through there is no such field, if returned Field object. If not, open a infinite loop looking for from its parent class, if the class has no parent or have been found Object
class also can not be found to this method, the description field of this class is really not looking, throw an exception. If you find this field in its parent class, returns a field object.
findFieldRecursiveImpl end of the call, will be back after findField the second half:
public static Field findField(Class<?> clazz, String fieldName) {
......
try {
Field field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException e) {
fieldCache.put(fullFieldName, null);
throw new NoSuchFieldError(fullFieldName);
}
}
If findFieldRecursiveImpl not throw an exception, then the field will be added to the cache, and returns this field. If you throw an exception if findFieldRecursiveImpl, also placed in the cache, but put a null value.
findField
End of the process, back to the original getObjectField
method, call the get
method to return the field to store object values
Value of a field
And a method to get the value of the field, like setting method also has many fields, their implementation is also very much the same we take a look at `setObjectField`` of these methods:
public static void setObjectField(Object obj, String fieldName, Object value) {
try {
findField(obj.getClass(), fieldName).set(obj, value);
} catch (IllegalAccessException e) {
// should not happen
XposedBridge.log(e);
throw new IllegalAccessError(e.getMessage());
} catch (IllegalArgumentException e) {
throw e;
}
}
setObjectField
And explain the above method getObjectField
is almost the same, but also by calling findField
to give the Field class object method. The difference is that, setObjectField
after the call is its object to give Field set method to set the value of the field