名词说明
谷歌虽然为开发者提供了众多api接口,但是对于一些个别情况这些api还是不够的,反射机制就是谷歌提供了另外一种扩充api接口的方式,只能在sdk源码中能够看到拥有@hide的标签,那么就可以使用反射来为我们使用,它作用于程序运行时状态。
使用方法案例
这里以Android的TelephonyManager类为例;
注:如果反射的类无法在sdk中获取到,可以使用如下方法:
Class> mClassType = Class.forName("android.view.SurfaceControl");
1. 当我们需要获取指定变量参数
如:我们希望获取ACTION_PRECISE_CALL_STATE_CHANGED这个变量的数据
mTm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
Field sField = mTm.getClass().getField("ACTION_PRECISE_CALL_STATE_CHANGED");
Log.d(TAG, "zly --> name: " + sField.getName() + " values:" + sField.get(MainActivity.this))
从上面可以看到这里使用了getField方法来进行获取变量的反射,这个方法只能反射public的修饰的变量,sField.get这个只能获取有值的变量,如果是Context context这种没有初始值的情况会异常报错,如果希望反射private 或者protecte的变量需要使用getDeclaredField方法,使用规则一样。getField和getDeclaredField的另外一个区别就是getDeclaredField只能获取本类里的变量,父类变量无法反射,getField则都能反射。
2. 当我们需要获取指定方法
如我们需要获取TelephonyManager的getSimState方法并且是带参数的。
Class clazz = TelephonyManager.class;
Method method = clazz.getMethod("getSimState", int.class);
Log.d(TAG, "zly --> simState:" + (int) method.invoke(mTm, 0));
从上述代码中可以看到首先在创建一个TelephonyManager的Class类,再通过这个类的getMethod得到我们需要的方法,getMethod方法参数如下:
Method getMethod(String name, Class...> parameterTypes)
第一个参数是我们需要获取的方法名;
后面的参数和我们获取方法的参数相对应,如getSimState只有一个int参数那么这里就写int.class
同样这里的getMethod方法也是只能获取public修饰的方法,如果需要获取其它类型的,需要使用getDeclaredMethod,使用规则及原理同上面提到的getDeclaredField。
还有一种方法可以找到我们指定的反射变和或方法,并不推荐这种,知道就好。
private void printAllFileds() {
Field[] field = mTm.getClass().getDeclaredFields();
Field f;
for (int i = 0; i < field.length; i++) {
f = field[i];
Log.d(TAG, "zly --> Field Name = " + f.getName());
}
}
private void printAllMethods() {
Method[] method = mTm.getClass().getDeclaredMethods();
for (Method m : method) {
System.out.println("Method Name = " + m.getName());
}
}
使用总结
1,必须要有@hide修饰,否则无法反射
2,getField,getMethod只能反射public类型的数据,getDeclaredField,getDeclaredMethods可以反射任何类型的数据。
3,getField,getMethod可以反射父类的数据,而getDeclaredField,getDeclaredMethods只能获取当前类的数据。
4,对于private static final 这种方法或者变量反射时无法调用,需要在下面执行
method.setAccessible(true);