Java動的エージェント運用の実現Xutils注入モジュール

13180 ワード

一.前文は前の文章の学习を通じて、私达はダイナミックエージェントに対して相対的に深い认识があることを信じて、今日私达はダイナミックエージェントを使うことを通じてXutilsの中の注入を完成します.二.エージェントオブジェクトの機能は、エージェントオブジェクトによって実現できる2つの機能であり、1つは機能強化であり、もう1つは方法のブロックであり、実際には機能強化もブロック方法によって実現される.エージェントオブジェクトと被エージェントオブジェクトは同じインタフェースを実現しているため、すべての彼らのタイプは完全に同じであり、この点を運用して、必要なときにオブジェクトを盗んで、いくつかの特殊な機能3を完成することができる.プロジェクト分析では、3つの作業、レイアウト注入、ビュー注入、イベント注入を完了します.そのうち、最初の2つは非常に簡単で、3つ目の作業に重点を置きます.ActivityでBaseActivityを実装し、onCreateメソッドを書き換えてこのメソッドでViewInjectUtilを呼び出す必要があります.inject(this);メソッドは、このメソッドですべての注入を完了し、Activityが作成されたときに親のメソッドを呼び出すので、すべての注入を早期に完了します.ViewInjectUtilのコードを見てください.
public class ViewInjectUtil {
          public static void inject(Activity activity){
              ViewLayoutInject.getInstance().inject(activity);
              ViewInstanceInject.getInstance().inject(activity);
              ViewEventInject.getInstance().inject(activity);
          }
}

このメソッドでは、レイアウト注入、ビュー注入、イベント注入をそれぞれ表し、BaseInject抽象クラスから継承されます.クラスには、抽出された汎用メソッドが1つしかありません.(1).レイアウトインジェクション
public  void inject(Activity t) {
        // TODO Auto-generated method stub
        Class calzz=t.getClass();
        Annotation annotation = calzz.getAnnotation(LayoutInject.class);
        if (annotation==null) {
            return;
        }
        LayoutInject layoutInject=(LayoutInject) annotation;
        int layoutVlaue=layoutInject.layout();
        Method method=null;
        try {
            method=calzz.getDeclaredMethod(METHOD_NAME, new Class[]{int.class});
            method.invoke(t, layoutVlaue);
        }catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

レイアウト注入のコード、レイアウト注入の注釈クラスを見てみましょう
@Retention(value =RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE })
public @interface LayoutInject {
           int layout();
}

この2つのセグメントのコードは非常に簡単で、まずActivityのインスタンスからバイトコードオブジェクトを逆方向に取得し、バイトコードオブジェクトからクラスに作用するLayoutInjectの注釈を取得し、その後、注釈から値を取得します.これは私たちが注入するレイアウトidです.バイトコードからsetContentViewメソッドのMethodオブジェクトを取得し、invokeメソッドを呼び出し、作用オブジェクトとレイアウトパラメータを入力すればよい.(2).ビューインジェクション
public void inject(Activity activity) {
        // TODO Auto-generated method stub
        Class clazz=(Class) activity.getClass();
        Field[] fields=clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field=fields[i];
            Annotation annotation=field.getAnnotation(ViewInject.class);
            if (annotation!=null) {
               ViewInject viewInjectAnnotation=(ViewInject) annotation;
               int viewId=viewInjectAnnotation.value();
            try {
                Method findMethod=clazz.getMethod(METHOD_NAME, int.class);
                Object view=findMethod.invoke(activity, viewId);
                field.setAccessible(true);
                field.set(activity, view);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            }
        }
    }

ビュー注記クラス
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
      int value();
}

ビュー注入の考え方とレイアウト注入は基本的に似ており、Activityインスタンスを介して対応するバイトコードオブジェクトを逆方向に取得し、すべてのFieldオブジェクトを取得し、Fieldオブジェクトに作用する注釈を取得し、この注釈がViewInjectタイプであれば注釈の値を取得します.これは私たちが注入するコントロールのidであり、findViewByIdメソッドのMethodオブジェクトを取得します.invokeメソッドを呼び出して返されるオブジェクトを取得します.これが、私たちが検索するviewオブジェクトです.最後にfieidオブジェクトのsetメソッドを呼び出して対応する値を設定します.(3).イベントの注入コントロールのイベントタイプはsetOnClickListener,setOnLoneClickListenerタイプ,対応するインタフェースはOnClickListenerとOnLongClickListener,対応するコールバックメソッドはonClickとonLongClickメソッドである.観察により,注入イベントの3要素はsetXXXメソッド,インタフェース,onXXXメソッドであり,この3要素を決定するとクリックイベントが決定されるので,この3要素を1つの注釈として抽出できることが分かった.
@Target(ElementType.ANNOTATION_TYPE)
@Retention(value =RetentionPolicy.RUNTIME)
public @interface BaseEvent {
     //onClick,onLongClick
     String callBackName();
     //setOnClickListener setOnLongClickListener
     String viewMethodName();
     //OnClickListener.class
     Class eventInterface();
}
        BaseEvent  ,            ,                   ,                      ,           。
@Target(value = { ElementType.METHOD})
@Retention(value =RetentionPolicy.RUNTIME)
@BaseEvent(eventInterface =OnClickListener.class, 
callBackName = "onClick", viewMethodName = "setOnClickListener")
public @interface ClickEvent {
      int value();
}
       onClick  ,          BaseEvent        ,        ,       OnLongClick   ,            ,             Activity    ,          。
    @ClickEvent(value =R.id.button)
    public void method1(View view){
        Log.d("ViewEventInject", "      ");
    }

イベントインジェクションの目的は,メソッドにClickEvent注釈を作用させることであり,buttonをクリックするとmethod 1メソッドが呼び出され,まず通常のメソッドがどのように行われているかを見ることである.
button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });
        ,            OnClickListener        null,    null,       OnClick  ,   View      。           onClick         Activity        method1   Method  ,    invoke    View    。
               OnClickListener      ,             ,     View  ,  view        ,  setOnClickListener   Method  ,            OnClickListener      ,    id       Method       Map , onClick          Method  ,          。
     ,                    ,           ,              ,               。                   ,                      。       ,             ,  JDK                    ,               ,                 Method        Method  。               ,         setOnClickListener     。           ,        onClick       。
    EventInvocationHandler   
public class EventInvocationHandler implements InvocationHandler {
    //      , Activity ,     Activity
    private Method method;
    private Object receiver;
    public EventInvocationHandler(Method method,Object receiver) {
        // TODO Auto-generated constructor stub
        this.method=method;
        this.receiver=receiver;
    }
    //          OnClick   ,        ,     
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub
        //    
        this.method.invoke(receiver, args);
        return proxy;
    }

}
          ,invoke         ,this.method.invoke(receiver, args)          Activity  method1  ,     ,         onClick      ,              ,         incoke  ,              ,              。
   ViewEventInject     
public void inject(Activity activity) {
        // TODO Auto-generated method stub
        Class clazz=(Class) activity.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method=methods[i];
            Annotation[] annotations = method.getAnnotations();
            for (int j = 0; j < annotations.length; j++) {
                Annotation annotation=annotations[j];

                Class annotationClazz=annotation.annotationType();
                //           ClickEvent  
                if (!method.isAnnotationPresent(ClickEvent.class)) {
                    //  ClickEvent   OnClickEvent    

                    continue;
                }
                ClickEvent clickEvent=(ClickEvent) annotation;
                int viewId=clickEvent.value();

                BaseEvent baseEvent=(BaseEvent) annotationClazz.getAnnotation(BaseEvent.class);
               //        
               Class eventClazz=baseEvent.eventInterface();
               String eventMethodName=baseEvent.callBackName();
               String viewMethodName = baseEvent.viewMethodName();

               View view=activity.findViewById(viewId);
               //      ,           
               EventInvocationHandler eventInvocationHandler=new EventInvocationHandler(method,activity);
               Object proxy=Proxy.newProxyInstance(eventClazz.getClassLoader(), new Class[]{eventClazz}, eventInvocationHandler);
               Method setMethod;
            try {
                setMethod = view.getClass().getMethod(viewMethodName,eventClazz);
                setMethod.invoke(view, proxy);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            }
        }
    }
     ,  Activity    ,       ,      ClickEvent       ,  ClickEvent     ,             id,              。  id  View  ,  Proxy.newProxyInstance(eventClazz.getClassLoader(), new Class[]{eventClazz}, eventInvocationHandler);  。                    ,                ,   EventInvocationHandler  。           , view          setXXX  ,             ,    Method  ,  invoke    view        ,            ,

ここまですべての注入作業が完了しました.四.このいくつかの文章の学習を総括して、Javaの中の反射、汎型と注釈と動的dエージェントモードに対して相対的に深い理解を持って、今日コードを必要とする学生は私たちのコードをダウンロードして勉強することができて、間違ったところがあっても共同学習を指摘することができます.コードのダウンロード