Androidの反射への応用

5043 ワード

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が実際に呼び出すのはgetField 0である.彼らは最後に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の例をダウンロードして、反射に関するアプリケーションを表示することができます.