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的例子来查看反射的相关应用。

更多相关文章

  1. 对于Android日夜间模式实现的探讨
  2. 高效android编程
  3. Android平台上四种保存数据的方法
  4. android ctivity完美退出
  5. Android自动接听&挂断电话(包含怎么应对4.1以上版本的权限检查)
  6. Android(安卓)侧滑关闭Activity的实例
  7. android listView 到上下边界 蓝色或黄色阴影去除方法
  8. android fragment详细介绍
  9. 【已解决】Android(安卓)Studio中不能使用JavaBean中的BeanInfo

随机推荐

  1. Android(安卓)MIME类型与文件后缀名匹配
  2. LinearLayout中设置 水平且垂直 居中
  3. GridView 实现水平拖拉效果
  4. Android(安卓)APK 反编译工具
  5. Android(安卓)改变ImageView图片的Bitmap
  6. android 还原短信
  7. android studio在终端执行gradlew命令,报
  8. andoird HTTP 工具类
  9. Android(安卓)关机(reboot)流程
  10. android中ImageView、ImageButton、Butto