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,应用)