在android开发中经常会用到反射的知识,举几个反射的例子分析反射。
在android中有些源码中的类是hide的or私有的,我们不能够直接得到具体的对象,但是这些类在我们应用程序运行之后他的对象确实是被创建并且存在于内存中的,只是是私有的,我们直接拿不到,所以就需要通过反射去得到这个对象,但是我们通过反射得到的对象并不是我们运行程序中代码使用的对象,反射得到的是新的对象,所以我们就需要把这个新的对象和我们运行程序相关联进而得到我们运行程序中的对象。
1. 反射修改TabLayout的下划线线宽
/**
* Set tabLayout indicator width by reflection.
*
* @param tabLayout tabLayout.
*/
public static void setTabLayoutIndicator(final TabLayout tabLayout) {
// The width of the line is set according to the width of the tabView.
tabLayout.post(new Runnable() {
@Override
public void run() {
try {
Field field = tabLayout.getClass().getDeclaredField("mTabStrip");
field.setAccessible(true);
//Get the attributes of tabLayout mTabStrip.
for (int i = 0, count = tabStrip.getChildCount(); i < count; i++) {
View tabView = tabStrip.getChildAt(i);
//Get the attributes of tabView mTextView.
Field textViewField = tabView.getClass().getDeclaredField("mTextView");
textViewField.setAccessible(true);
TextView textView = (TextView) textViewField.get(tabView);
tabView.setPadding(0, 0, 0, 0);
// Measure the width of indicator according to text view.
int textWidth = 0;
textWidth = textView.getWidth();
if (textWidth == 0) {
textView.measure(0, 0);
textWidth = textView.getMeasuredWidth();
}
int tabWidth = 0;
tabWidth = tabView.getWidth();
if (tabWidth == 0) {
tabView.measure(0, 0);
tabWidth = tabView.getMeasuredWidth();
}
// Set tabView layoutParams.
LinearLayout.LayoutParams tabViewParams = (LinearLayout.LayoutParams) tabView
.getLayoutParams();
int margin = (tabWidth - textWidth) / 2;
tabViewParams.leftMargin = margin;
tabViewParams.rightMargin = margin;
tabViewParams.topMargin = INDICATOR_MARGIN_TOP;
tabView.setLayoutParams(tabViewParams);
}
} catch (NoSuchFieldException exception) {
Log.e(TAG, "setIndicatorWidth: get tabStrip failed.");
} catch (IllegalAccessException exception) {
Log.e(TAG, "setIndicatorWidth: get LinearLayout failed.");
}
}
});
}
通过对tabLayout反射拿到他的一个属性tabStrip对象,然后通过 LinearLayout tabStrip = (LinearLayout) field.get(tabLayout); 进行关联,得到的就行我们运行程序中TabLayout中的tabStrip对象,就是运行程序中当前使用的对象。
2.反射控制status bar的显示隐藏
public static void setStatusBarState(Context context, int disableFlag) {
Object service = context.getSystemService("statusbar");
try {
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method disable = statusbarManager.getMethod(disable, int.class);
disable.invoke(service, disableFlag);
} catch (IllegalAccessException exception) {
Log.e(TAG, "IllegalAccessException: ", exception);
} catch (InvocationTargetException exception) {
Log.e(TAG, "InvocationTargetException: ", exception);
} catch (ClassNotFoundException exception) {
Log.e(TAG, "ClassNotFoundException: ", exception);
} catch (NoSuchMethodException exception) {
Log.e(TAG, "NoSuchMethodException: ", exception);
}
}
StatusBarManager我们正常是访问不到这个类的,他是hide的。所以我们通过得到object对象接收,最后通过disable.invoke(service, disableFlag);进行和我们context中的对象关联。
3.动态代理替换
public void replaceActivitytat(Activity activity){
//得到 Activity 的 minstrumentation 字段
Field field = Activity.class.getDeclaredField("minstrumentation");
//取消 Java 的权限控制检查
field.setAccessible(true) ;
Instrumentation instrumentation= (Instrumentation) field.get(activity);
Instrumentation instrumentationProxy = new InstrumentationProxy(instrumentation);
field.set(activity , instrumentationProxy);
}
field.get(activity)通过得到当前Activity中的 minstrumentation 实例对象,传递给代理类。最后用instrumentationProxy把minstrumentation实例替换掉。在程序运行的时候运行的就是instrumentationProxy。
总结:
- 直接反射的来的对象并不是我们当前运行内存中使用的对象,他是一个新对象。
- 跟我们当前能处理的对象,与反射得到的新对象进行关联。
关联的方式 1.如果是属性 field.set(object,value) 和 field.get(object)
2.如果是方法 medthod.invoke(object,value); - 关联之后的对象就是我们当前内存中使用的对象