Android之对反射的应用
1.反射基本概念
因为反射其实就是java的一个机制,所以说android的反射其实是对它的一个应用。
在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,可以参考这里对反射的解释。
2.反射调用的基本方法
getDeclaredField是可以获取一个类的所有字段.
getField只能获取类的public 字段.
1. public Field getDeclaredField(String name) 2. throws NoSuchFieldException, SecurityException { 3. checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); 4. Field field = searchFields(privateGetDeclaredFields(false), name); 5. if (field == null) { 6. throw new NoSuchFieldException(name); 7. } 8. return field; 9. } 10. 11. 12. private Field getField0(String name) throws NoSuchFieldException { 13. Field res = null; 14. // Search declared public fields 15. if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) { 16. return res; 17. } 18. ......
getField其实调用的是getField0.
他们最后都调用了searchFields.
不过getDeclaredField传入的是privateGetDeclaredFields(false),
getField传入的是privateGetDeclaredFields(true),
1. private Field[] privateGetDeclaredFields(boolean publicOnly) { 2. checkInitted(); 3. Field[] res = null; 4. if (useCaches) { 5. clearCachesOnClassRedefinition(); 6. if (publicOnly) { 7. if (declaredPublicFields != null) { 8. res = (Field[]) declaredPublicFields.get(); 9. } 10. } else { 11. if (declaredFields != null) { 12. res = (Field[]) declaredFields.get(); 13. } 14. }
可以看到传入条件为true的时候使用的是declaredPublicFields,意思是public字段
为false的时候使用的是declaredFields.
例如修改Android原生SDK中的MediaController可以通过以下方法:
mView = LayoutInflater.from(getContext()).inflate( R.layout.my_control, null); try { Field mRoot = android.widget.MediaController.class .getDeclaredField("mRoot"); mRoot.setAccessible(true); ViewGroup mRootVg = (ViewGroup) mRoot.get(this); mRootVg.removeAllViews(); initControllerView(); mRootVg.addView(mView); } catch (Exception e) { e.printStackTrace(); }}private void initControllerView() throws Exception{ Field mPauseButtonField = android.widget.MediaController.class.getDeclaredField("mPauseButton"); if (mPauseButtonField != null) { mPauseButtonField.setAccessible(true); mPauseButtonField.set(this,mView.findViewById(R.id.pause)); } Field mListenerField = android.widget.MediaController.class.getDeclaredField("mPauseListener"); if (mPauseButtonField != null && mListenerField != null) { mListenerField.setAccessible(true); ((ImageButton)mPauseButtonField.get(this)).setOnClickListener(( View.OnClickListener)mListenerField.get(this)); } Field mProgressFiled = android.widget.MediaController.class.getDeclaredField("mProgress");{ if (mProgressFiled != null) { mProgressFiled.setAccessible(true); mProgressFiled.set(this,mView.findViewById(R.id.mediacontroller_progress)); } } Field mSeekListenerField = android.widget.MediaController.class.getDeclaredField("mSeekListener"); if (mSeekListenerField != null && mProgressFiled != null) { mSeekListenerField.setAccessible(true); ProgressBar mProgress = (ProgressBar)mProgressFiled.get(this); if (mProgress instanceof SeekBar) { SeekBar seeker = (SeekBar) mProgress; seeker.setOnSeekBarChangeListener((SeekBar.OnSeekBarChangeListener)mSeekListenerField.get(this)); } mProgress.setMax(100); } Field mEndTimeFiled = android.widget.MediaController.class.getDeclaredField("mEndTime"); if (mEndTimeFiled != null) { mEndTimeFiled.setAccessible(true); mEndTimeFiled.set(this,mView.findViewById(R.id.time_end)); } Field mCurrentTimeFiled = android.widget.MediaController.class.getDeclaredField("mCurrentTime"); if (mCurrentTimeFiled != null) { mCurrentTimeFiled.setAccessible(true); mCurrentTimeFiled.set(this,mView.findViewById(R.id.time_current)); }}
由此可以看出,如果当我们要修改某些代码的时候但是又没有源码,可以用到反射机制,但是反射的运用不简简单单就是这样。
3.反射的高级运用
当我们有时候需要反射劫持到某个方法的时候,因为我们想修改该方法,但是仅仅是添加某些东西,而又不想修改它的基本逻辑,这时候可以用到劫持机制。
劫持,什么叫劫持呢,其实就是替换字段,有人说你直接反射拿到变量,直接反射替换就是了,这是一种方式,但是这并不是我想要的,比如我要劫持Student里的behavior变量,但是我不想修改它,我想保留它原来的逻辑,但是我又想加入新的东西,这个就有点类型面向切面编程了,比如日志的注入。怎么做?显然是动态代理啊。使用代理类去完成劫持操作,既可以保留原有操作,又可以增加新的逻辑。
可以通过这里下载MediaController的例子来查看反射的相关应用。
更多相关文章
- 对于Android日夜间模式实现的探讨
- 高效android编程
- Android平台上四种保存数据的方法
- android ctivity完美退出
- Android自动接听&挂断电话(包含怎么应对4.1以上版本的权限检查)
- Android(安卓)侧滑关闭Activity的实例
- android listView 到上下边界 蓝色或黄色阴影去除方法
- android fragment详细介绍
- 【已解决】Android(安卓)Studio中不能使用JavaBean中的BeanInfo