亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android應(yīng)用開發(fā)中控制反轉(zhuǎn)IoC設(shè)計(jì)模式使用教程

 更新時(shí)間:2024年07月12日 17:06:38   作者:鴻洋_  
這篇文章主要介紹了Android應(yīng)用開發(fā)中控制反轉(zhuǎn)IoC設(shè)計(jì)模式使用教程,IoC其實(shí)更常被理解為一種依賴注入的模式,用來分解業(yè)務(wù)層降低耦合,需要的朋友可以參考下

1、概述
首先我們來吹吹牛,什么叫IoC,控制反轉(zhuǎn)(Inversion of Control,英文縮寫為IoC),什么意思呢?
就是你一個(gè)類里面需要用到很多個(gè)成員變量,傳統(tǒng)的寫法,你要用這些成員變量,那么你就new 出來用唄~~
IoC的原則是:NO,我們不要new,這樣耦合度太高;你配置個(gè)xml文件,里面標(biāo)明哪個(gè)類,里面用了哪些成員變量,等待加載這個(gè)類的時(shí)候,我?guī)湍阕⑷耄╪ew)進(jìn)去;
這樣做有什么好處呢?
 回答這個(gè)問題,剛好可以回答另一個(gè)問題,很多人問,項(xiàng)目分層開發(fā)是吧,分為控制層、業(yè)務(wù)層、DAO層神馬的。然后每一層為撒子要一個(gè)包放接口,一個(gè)包放實(shí)現(xiàn)呢?只要一個(gè)實(shí)現(xiàn)包不行么~剛好,如果你了解了IoC,你就知道這些個(gè)接口的作用了,上面不是說,你不用new,你只要聲明了成員變量+寫個(gè)配置文件,有人幫你new;此時(shí),你在類中,就可以把需要使用到的成員變量都聲明成接口,然后你會(huì)發(fā)現(xiàn),當(dāng)實(shí)現(xiàn)類發(fā)生變化的時(shí)候,或者切換實(shí)現(xiàn)類,你需要做什么呢?你只要在配置文件里面做個(gè)簡(jiǎn)單的修改。如果你用的就是實(shí)實(shí)在在的實(shí)現(xiàn)類,現(xiàn)在換實(shí)現(xiàn)類,你需要找到所有聲明這個(gè)實(shí)現(xiàn)類的地方,手動(dòng)修改類名;如果你遇到了一個(gè)多變的老大,是吧,呵呵~
 當(dāng)然了,很多會(huì)覺得,寫個(gè)配置文件,這多麻煩。于是乎,又出現(xiàn)了另一種方案,得,你閑配置文件麻煩,你用注解吧。你在需要注入的成員變量上面給我加個(gè)注解,例如:@Inject,這樣就行了,你總不能說這么個(gè)單詞麻煩吧~~
 當(dāng)然了,有了配置文件和注解,那么怎么注入呢?其實(shí)就是把字符串類路徑變成類么,當(dāng)然了,反射上場(chǎng)了;話說,很久很久以前,反射很慢啊,嗯,那是很久很久以前,現(xiàn)在已經(jīng)不是太慢了,當(dāng)然了肯定達(dá)不到原生的速度~~無反射,沒有任何框架。
 如果你覺得注解,反射神馬的好高級(jí)。我說一句:Just Do It ,你會(huì)發(fā)現(xiàn)注解就和你寫一個(gè)普通JavaBean差不多;反射呢?API就那么幾行,千萬不要被震懾住~

2、框架實(shí)現(xiàn)
得進(jìn)入正題了,Android IOC框架,其實(shí)主要就是幫大家注入所有的控件,布局文件什么的。如果你用過xUtils,afinal類的框架,你肯定不陌生~
注入View
假設(shè):我們一個(gè)Activity,里面10來個(gè)View。
傳統(tǒng)做法:我們需要先給這個(gè)Activity設(shè)置下布局文件,然后在onCreate里面一個(gè)一個(gè)的findViewById把~
目標(biāo)的做法:Activity類上添加個(gè)注解,幫我們自動(dòng)注入布局文科;聲明View的時(shí)候,添加一行注解,然后自動(dòng)幫我們findViewById;
于是乎我們的目標(biāo)類是這樣的:
 

@ContentView(value = R.layout.activity_main) 
public class MainActivity extends BaseActivity 
{ 
 @ViewInject(R.id.id_btn) 
 private Button mBtn1; 
 @ViewInject(R.id.id_btn02) 
 private Button mBtn2; 

3、編碼
(1)定義注解

首先我們需要兩個(gè)注解文件:

package com.zhy.ioc.view.annotation; 
 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface ContentView 
{ 
 int value(); 
} 

ContentView用于在類上使用,主要用于標(biāo)明該Activity需要使用的布局文件。

 @ContentView(value = R.layout.activity_main) 
public class MainActivity 

 
package com.zhy.ioc.view.annotation; 
 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface ViewInject 
{ 
 int value(); 
} 

在成員變量上使用,用于指定View的Id

@ViewInject(R.id.id_btn) 
 private Button mBtn1; 

簡(jiǎn)單說一下注解:定義的關(guān)鍵字@interface ; @Target表示該注解可以用于什么地方,可能的類型TYPE(類),FIELD(成員變量),可能的類型:

public enum ElementType { 
 /** 
  * Class, interface or enum declaration. 
  */ 
 TYPE, 
 /** 
  * Field declaration. 
  */ 
 FIELD, 
 /** 
  * Method declaration. 
  */ 
 METHOD, 
 /** 
  * Parameter declaration. 
  */ 
 PARAMETER, 
 /** 
  * Constructor declaration. 
  */ 
 CONSTRUCTOR, 
 /** 
  * Local variable declaration. 
  */ 
 LOCAL_VARIABLE, 
 /** 
  * Annotation type declaration. 
  */ 
 ANNOTATION_TYPE, 
 /** 
  * Package declaration. 
  */ 
 PACKAGE 
} 

就是這些個(gè)枚舉。
@Retention表示:表示需要在什么級(jí)別保存該注解信息;我們這里設(shè)置為運(yùn)行時(shí)。
可能的類型: 

public enum RetentionPolicy { 
 /** 
  * Annotation is only available in the source code. 
  */ 
 SOURCE, 
 /** 
  * Annotation is available in the source code and in the class file, but not 
  * at runtime. This is the default policy. 
  */ 
 CLASS, 
 /** 
  * Annotation is available in the source code, the class file and is 
  * available at runtime. 
  */ 
 RUNTIME 
} 

這些個(gè)枚舉~

(2)MainActivity

package com.zhy.zhy_xutils_test; 
 
import android.app.Activity; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.Toast; 
 
import com.zhy.ioc.view.ViewInjectUtils; 
import com.zhy.ioc.view.annotation.ContentView; 
import com.zhy.ioc.view.annotation.ViewInject; 
 
@ContentView(value = R.layout.activity_main) 
public class MainActivity extends Activity implements OnClickListener 
{ 
 @ViewInject(R.id.id_btn) 
 private Button mBtn1; 
 @ViewInject(R.id.id_btn02) 
 private Button mBtn2; 
 
 @Override 
 protected void onCreate(Bundle savedInstanceState) 
 { 
  super.onCreate(savedInstanceState); 
   
  ViewInjectUtils.inject(this); 
 
  mBtn1.setOnClickListener(this); 
  mBtn2.setOnClickListener(this); 
 } 
 
 @Override 
 public void onClick(View v) 
 { 
  switch (v.getId()) 
  { 
  case R.id.id_btn: 
   Toast.makeText(MainActivity.this, "Why do you click me ?", 
     Toast.LENGTH_SHORT).show(); 
   break; 
 
  case R.id.id_btn02: 
   Toast.makeText(MainActivity.this, "I am sleeping !!!", 
     Toast.LENGTH_SHORT).show(); 
   break; 
  } 
 } 
 
} 

注解都寫好了,核心的代碼就是ViewInjectUtils.inject(this)了~

(3)ViewInjectUtils
A、首先是注入主布局文件的代碼:

/** 
  * 注入主布局文件 
  * 
  * @param activity 
  */ 
 private static void injectContentView(Activity activity) 
 { 
  Class<? extends Activity> clazz = activity.getClass(); 
  // 查詢類上是否存在ContentView注解 
  ContentView contentView = clazz.getAnnotation(ContentView.class); 
  if (contentView != null)// 存在 
  { 
   int contentViewLayoutId = contentView.value(); 
   try 
   { 
    Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW, 
      int.class); 
    method.setAccessible(true); 
    method.invoke(activity, contentViewLayoutId); 
   } catch (Exception e) 
   { 
    e.printStackTrace(); 
   } 
  } 
 } 

通過傳入的activity對(duì)象,獲得它的Class類型,判斷是否寫了ContentView這個(gè)注解,如果寫了,讀取它的value,然后得到setContentView這個(gè)方法,使用invoke進(jìn)行調(diào)用;
有個(gè)常量:

private static final String METHOD_SET_CONTENTVIEW = "setContentView"; 

B、接下來是注入Views

private static final String METHOD_FIND_VIEW_BY_ID = "findViewById"; 
 /** 
  * 注入所有的控件 
  * 
  * @param activity 
  */ 
 private static void injectViews(Activity activity) 
 { 
  Class<? extends Activity> clazz = activity.getClass(); 
  Field[] fields = clazz.getDeclaredFields(); 
  // 遍歷所有成員變量 
  for (Field field : fields) 
  { 
    
   ViewInject viewInjectAnnotation = field 
     .getAnnotation(ViewInject.class); 
   if (viewInjectAnnotation != null) 
   { 
    int viewId = viewInjectAnnotation.value(); 
    if (viewId != -1) 
    { 
     Log.e("TAG", viewId+""); 
     // 初始化View 
     try 
     { 
      Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID, 
        int.class); 
      Object resView = method.invoke(activity, viewId); 
      field.setAccessible(true); 
      field.set(activity, resView); 
     } catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
 
    } 
   } 
 
  } 
 
 } 

獲取聲明的所有的屬性,遍歷,找到存在ViewInject注解的屬性,或者其value,然后去調(diào)用findViewById方法,最后把值設(shè)置給field~~~
好了,把這兩個(gè)方法寫到inject里面就好了。

 public static void inject(Activity activity) 
 { 
   
  injectContentView(activity); 
  injectViews(activity); 
   
 } 

效果圖:

2016426142543030.gif (382×658)

4.View的事件的注入
光有View的注入能行么,我們寫View的目的,很多是用來交互的,得可以點(diǎn)擊神馬的吧。摒棄傳統(tǒng)的神馬,setOnClickListener,然后實(shí)現(xiàn)匿名類或者別的方式神馬的,我們改變?yōu)椋?/p>

package com.zhy.zhy_xutils_test; 
 
import android.view.View; 
import android.widget.Button; 
import android.widget.Toast; 
 
import com.zhy.ioc.view.annotation.ContentView; 
import com.zhy.ioc.view.annotation.OnClick; 
import com.zhy.ioc.view.annotation.ViewInject; 
 
@ContentView(value = R.layout.activity_main) 
public class MainActivity extends BaseActivity 
{ 
 @ViewInject(R.id.id_btn) 
 private Button mBtn1; 
 @ViewInject(R.id.id_btn02) 
 private Button mBtn2; 
 
 @OnClick({ R.id.id_btn, R.id.id_btn02 }) 
 public void clickBtnInvoked(View view) 
 { 
  switch (view.getId()) 
  { 
  case R.id.id_btn: 
   Toast.makeText(this, "Inject Btn01 !", Toast.LENGTH_SHORT).show(); 
   break; 
  case R.id.id_btn02: 
   Toast.makeText(this, "Inject Btn02 !", Toast.LENGTH_SHORT).show(); 
   break; 
  } 
 } 
 
} 

直接通過在Activity中的任何一個(gè)方法上,添加注解,完成1個(gè)或多個(gè)控件的事件的注入。這里我把onCreate搬到了BaseActivity中,里面調(diào)用了ViewInjectUtils.inject(this);

(1)注解文件

package com.zhy.ioc.view.annotation; 
 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
@Target(ElementType.ANNOTATION_TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface EventBase 
{ 
 Class<?> listenerType(); 
 
 String listenerSetter(); 
 
 String methodName(); 
} 

 
package com.zhy.ioc.view.annotation; 
 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
import android.view.View; 
 
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@EventBase(listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick") 
public @interface OnClick 
{ 
 int[] value(); 
} 

EventBase主要用于給OnClick這類注解上添加注解,畢竟事件很多,并且設(shè)置監(jiān)聽器的名稱,監(jiān)聽器的類型,調(diào)用的方法名都是固定的,對(duì)應(yīng)上面代碼的:

復(fù)制代碼 代碼如下:

listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick"

Onclick是用于寫在Activity的某個(gè)方法上的:
 @OnClick({ R.id.id_btn, R.id.id_btn02 }) 
 public void clickBtnInvoked(View view) 

如果你還記得,上篇博客我們的ViewInjectUtils.inject(this);里面已經(jīng)有了兩個(gè)方法,本篇多了一個(gè):
 

public static void inject(Activity activity) 
 { 
  injectContentView(activity); 
  injectViews(activity); 
  injectEvents(activity); 
 } 

(2)injectEvents

/** 
  * 注入所有的事件 
  * 
  * @param activity 
  */ 
 private static void injectEvents(Activity activity) 
 { 
   
  Class<? extends Activity> clazz = activity.getClass(); 
  Method[] methods = clazz.getMethods(); 
  //遍歷所有的方法 
  for (Method method : methods) 
  { 
   Annotation[] annotations = method.getAnnotations(); 
   //拿到方法上的所有的注解 
   for (Annotation annotation : annotations) 
   { 
    Class<? extends Annotation> annotationType = annotation 
      .annotationType(); 
    //拿到注解上的注解 
    EventBase eventBaseAnnotation = annotationType 
      .getAnnotation(EventBase.class); 
    //如果設(shè)置為EventBase 
    if (eventBaseAnnotation != null) 
    { 
     //取出設(shè)置監(jiān)聽器的名稱,監(jiān)聽器的類型,調(diào)用的方法名 
     String listenerSetter = eventBaseAnnotation 
       .listenerSetter(); 
     Class<?> listenerType = eventBaseAnnotation.listenerType(); 
     String methodName = eventBaseAnnotation.methodName(); 
 
     try 
     { 
      //拿到Onclick注解中的value方法 
      Method aMethod = annotationType 
        .getDeclaredMethod("value"); 
      //取出所有的viewId 
      int[] viewIds = (int[]) aMethod 
        .invoke(annotation, null); 
      //通過InvocationHandler設(shè)置代理 
      DynamicHandler handler = new DynamicHandler(activity); 
      handler.addMethod(methodName, method); 
      Object listener = Proxy.newProxyInstance( 
        listenerType.getClassLoader(), 
        new Class<?>[] { listenerType }, handler); 
      //遍歷所有的View,設(shè)置事件 
      for (int viewId : viewIds) 
      { 
       View view = activity.findViewById(viewId); 
       Method setEventListenerMethod = view.getClass() 
         .getMethod(listenerSetter, listenerType); 
       setEventListenerMethod.invoke(view, listener); 
      } 
 
     } catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
 
   } 
  } 
 
 } 

嗯,注釋盡可能的詳細(xì)了,主要就是遍歷所有的方法,拿到該方法省的OnClick注解,然后再拿到該注解上的EventBase注解,得到事件監(jiān)聽的需要調(diào)用的方法名,類型,和需要調(diào)用的方法的名稱;通過Proxy和InvocationHandler得到監(jiān)聽器的代理對(duì)象,顯示設(shè)置了方法,最后通過反射設(shè)置監(jiān)聽器。
這里有個(gè)難點(diǎn),就是關(guān)于DynamicHandler和Proxy的出現(xiàn),如果不理解沒事,后面會(huì)詳細(xì)講解。

(3)DynamicHandler
這里用到了一個(gè)類DynamicHandler,就是InvocationHandler的實(shí)現(xiàn)類:

package com.zhy.ioc.view; 
 
import java.lang.ref.WeakReference; 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.util.HashMap; 
 
public class DynamicHandler implements InvocationHandler 
{ 
 private WeakReference<Object> handlerRef; 
 private final HashMap<String, Method> methodMap = new HashMap<String, Method>( 
   1); 
 
 public DynamicHandler(Object handler) 
 { 
  this.handlerRef = new WeakReference<Object>(handler); 
 } 
 
 public void addMethod(String name, Method method) 
 { 
  methodMap.put(name, method); 
 } 
 
 public Object getHandler() 
 { 
  return handlerRef.get(); 
 } 
 
 public void setHandler(Object handler) 
 { 
  this.handlerRef = new WeakReference<Object>(handler); 
 } 
 
 @Override 
 public Object invoke(Object proxy, Method method, Object[] args) 
   throws Throwable 
 { 
  Object handler = handlerRef.get(); 
  if (handler != null) 
  { 
   String methodName = method.getName(); 
   method = methodMap.get(methodName); 
   if (method != null) 
   { 
    return method.invoke(handler, args); 
   } 
  } 
  return null; 
 } 
} 

好了,代碼就這么多,這樣我們就實(shí)現(xiàn)了,我們事件的注入~~
效果圖:

2016426142746902.gif (382×658)

效果圖其實(shí)沒撒好貼的,都一樣~~~
(3)關(guān)于代理
那么,本文結(jié)束了么,沒有~~~關(guān)于以下幾行代碼,相信大家肯定有困惑,這幾行干了什么?

//通過InvocationHandler設(shè)置代理       

DynamicHandler handler = new DynamicHandler(activity); 
      handler.addMethod(methodName, method); 
      Object listener = Proxy.newProxyInstance( 
        listenerType.getClassLoader(), 
        new Class<?>[] { listenerType }, handler); 

InvocationHandler和Proxy成對(duì)出現(xiàn),相信大家如果對(duì)Java比較熟悉,肯定會(huì)想到Java的動(dòng)態(tài)代理~~~
關(guān)于InvocationHandler和Proxy的文章,大家可以參考:http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ ps:IBM的技術(shù)文章還是相當(dāng)不錯(cuò)的,畢竟有人審核還有獎(jiǎng)金~
但是我們的實(shí)現(xiàn)有一定的區(qū)別,我為什么說大家疑惑呢,比如反射實(shí)現(xiàn):
mBtn2.setOnClickListener(this);這樣的代碼,難點(diǎn)在哪呢?
A、mBtn2的獲???so easy
B、調(diào)用setOnClickListener ? so easy
but , 這個(gè) this,這個(gè)this是OnClickListener的實(shí)現(xiàn)類的實(shí)例,OnClickListener是個(gè)接口~~你的實(shí)現(xiàn)類怎么整,聽說過反射newInstance對(duì)象的,但是你現(xiàn)在是接口!
是吧~現(xiàn)在應(yīng)該明白上述幾行代碼做了什么了?實(shí)現(xiàn)了接口的一個(gè)代理對(duì)象,然后在代理類的invoke中,對(duì)接口的調(diào)用方法進(jìn)行處理。
(4)代碼是最好的老師
光說誰都理解不了,你在這xx什么呢??下面看代碼,我們模擬實(shí)現(xiàn)這樣一個(gè)情景:
Main類中實(shí)現(xiàn)一個(gè)Button,Button有兩個(gè)方法,一個(gè)setOnClickListener和onClick,當(dāng)調(diào)用Button的onClick時(shí),觸發(fā)的事件是Main類中的click方法
涉及到4個(gè)類:
Button

package com.zhy.invocationhandler; 
 
public class Button 
{ 
 private OnClickListener listener; 
 
 public void setOnClickLisntener(OnClickListener listener) 
 { 
 
  this.listener = listener; 
 } 
 
 public void click() 
 { 
  if (listener != null) 
  { 
   listener.onClick(); 
  } 
 } 
} 

OnClickListener接口

package com.zhy.invocationhandler; 
 
public interface OnClickListener 
{ 
 void onClick(); 
} 

OnClickListenerHandler , InvocationHandler的實(shí)現(xiàn)類

package com.zhy.invocationhandler; 
 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.util.HashMap; 
import java.util.Map; 
 
public class OnClickListenerHandler implements InvocationHandler 
{ 
 private Object targetObject; 
 
 public OnClickListenerHandler(Object object) 
 { 
  this.targetObject = object; 
 } 
 
 private Map<String, Method> methods = new HashMap<String, Method>(); 
 
 public void addMethod(String methodName, Method method) 
 { 
  methods.put(methodName, method); 
 } 
 
 @Override 
 public Object invoke(Object proxy, Method method, Object[] args) 
   throws Throwable 
 { 
 
  String methodName = method.getName(); 
  Method realMethod = methods.get(methodName); 
  return realMethod.invoke(targetObject, args); 
 } 
 
} 

我們的Main

package com.zhy.invocationhandler; 
 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
 
public class Main 
{ 
 private Button button = new Button(); 
  
 public Main() throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException 
 { 
  init(); 
 } 
 
 public void click() 
 { 
  System.out.println("Button clicked!"); 
 } 
 
 public void init() throws SecurityException, 
   NoSuchMethodException, IllegalArgumentException, 
   IllegalAccessException, InvocationTargetException 
 { 
  OnClickListenerHandler h = new OnClickListenerHandler(this); 
  Method method = Main.class.getMethod("click", null); 
  h.addMethod("onClick", method); 
  Object clickProxy = Proxy.newProxyInstance( 
    OnClickListener.class.getClassLoader(), 
    new Class<?>[] { OnClickListener.class }, h); 
  Method clickMethod = button.getClass().getMethod("setOnClickLisntener", 
    OnClickListener.class); 
  clickMethod.invoke(button, clickProxy); 
   
 } 
 
 public static void main(String[] args) throws SecurityException, 
   IllegalArgumentException, NoSuchMethodException, 
   IllegalAccessException, InvocationTargetException 
 { 
 
  Main main = new Main(); 
   
  main.button.click(); 
 } 
 
} 

我們模擬按鈕點(diǎn)擊:調(diào)用main.button.click(),實(shí)際執(zhí)行的卻是Main的click方法。
看init中,我們首先初始化了一個(gè)OnClickListenerHandler,把Main的當(dāng)前實(shí)例傳入,然后拿到Main的click方法,添加到OnClickListenerHandler中的Map中。
然后通過Proxy.newProxyInstance拿到OnClickListener這個(gè)接口的一個(gè)代理,這樣執(zhí)行這個(gè)接口的所有的方法,都會(huì)去調(diào)用OnClickListenerHandler的invoke方法。
但是呢?OnClickListener畢竟是個(gè)接口,也沒有方法體~~那咋辦呢?這時(shí)候就到我們OnClickListenerHandler中的Map中大展伸手了:

@Override
 public Object invoke(Object proxy, Method method, Object[] args)
 throws Throwable
 {
 String methodName = method.getName();
 Method realMethod = methods.get(methodName);
 return realMethod.invoke(targetObject, args);
 }

我們顯示的把要執(zhí)行的方法,通過鍵值對(duì)存到Map里面了,等調(diào)用到invoke的時(shí)候,其實(shí)是通過傳入的方法名,得到Map中存儲(chǔ)的方法,然后調(diào)用我們預(yù)設(shè)的方法~。
這樣,大家應(yīng)該明白了,其實(shí)就是通過Proxy得到接口的一個(gè)代理,然后在InvocationHandler中使用一個(gè)Map預(yù)先設(shè)置方法,從而實(shí)現(xiàn)Button的onClick,和Main的click關(guān)聯(lián)上。
現(xiàn)在看我們InjectEvents中的代碼:

//通過InvocationHandler設(shè)置代理 
      DynamicHandler handler = new DynamicHandler(activity); 
      //往map添加方法 
      handler.addMethod(methodName, method); 
      Object listener = Proxy.newProxyInstance( 
        listenerType.getClassLoader(), 
        new Class<?>[] { listenerType }, handler); 

是不是和我們init中的類似~~
好了,關(guān)于如何把接口的回調(diào)和我們Activity里面的方法關(guān)聯(lián)上我們也解釋完了~~~

注:部分代碼參考了xUtils這個(gè)框架,畢竟想很完善的實(shí)現(xiàn)一個(gè)完整的注入不是一兩篇博客就可以搞定,但是核心和骨架已經(jīng)實(shí)現(xiàn)了~~大家有興趣的可以繼續(xù)去完善~

相關(guān)文章

最新評(píng)論