> 文档中心 > 动态代理-事件注入(一)

动态代理-事件注入(一)


1.目的:

通过代理的方式去注册控件的点击事件,长按事件等其他事件。

  • 优点:隔离代码层,解耦
  • 缺点:运行时反射的效率低

2.第一版本(先不用动态代理):

2.1 创建一个注解类 (用来区分方法是否需要注册点击事件)

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface OnClick {    //接收控件的ID    int[] value() default -1;}

2.2 创建一个注解工具类

public class InjectUtil {    public static void init(Object content) { //1.获取类中所有的方法 Method[] methods = content.getClass().getMethods(); for (Method method : methods) {     //2.找到有标注注解的方法     OnClick onClick = method.getAnnotation(OnClick.class);     if (onClick != null) {  int[] value = onClick.value();  try {      //3.通过反射获取findViewById方法      Method findViewById = content.getClass().getMethod("findViewById", int.class);      for (int i : value) {   //4.获取控件   View view = (View) findViewById.invoke(content, i);   if (view != null) {//5.设置监听view.setOnClickListener(v -> {    try { //6.方法回调 method-> 就是我们外面标注注解的方法 method.invoke(content, v);    } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace();    }});   }      }  } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {      e.printStackTrace();  }     } }    }}

2.3 注册工具类

BaseActivity

public class BaseActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); InjectUtil.init(this);    }}

MainActivity

public class MainActivity extends BaseActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) { setContentView(R.layout.activity_main); super.onCreate(savedInstanceState);    }    @OnClick(R.id.btn)    public void start(View view) { Toast.makeText(this,"我被点击了",Toast.LENGTH_SHORT).show();    }}

注意:MainActivity类中,setContentView必须在super.onCreate()方法前,因为只有在setContentView后控件才会被创建。

很简单的代码,但这样会产生一个问题;
1.那就是如果你还要注册长按事件,viewpager的滑动事件,那是不是还得继续往文件写代码,违背了类的单一原则,也不好扩展,
2.你如何区分哪个控件需要长按,哪个不需要?按照下面的写法,所有的控件都会被自动注册长按事件,
如下长按事件;

view.setOnLongClickListener(new View.OnLongClickListener() {    @Override    public boolean onLongClick(View v) { //6.方法回调 method-> 就是我们外面标注注解的方法 try {     //6.方法回调 method-> 就是我们外面标注注解的方法     method.invoke(content, v); } catch (IllegalAccessException | InvocationTargetException e) {     e.printStackTrace(); } return false;    }});

接下来我们用动态代理看下,能不能解决上面的问题

3.使用动态代理:

我们简单的修改下InjectUtil

public static void init(Object content) {    //1.获取类中所有的方法    Method[] methods = content.getClass().getMethods();    for (Method method : methods) { //2.找到有标注注解的方法 OnClick onClick = method.getAnnotation(OnClick.class); if (onClick != null) {     int[] value = onClick.value();     try {  //3.通过反射获取findViewById方法  Method findViewById = content.getClass().getMethod("findViewById", int.class);  for (int i : value) {      //4.获取控件      View view = (View) findViewById.invoke(content, i);      //5.通过代理获取View.OnClickListener      View.OnClickListener listener = (View.OnClickListener) Proxy.newProxyInstance(content.getClass().getClassLoader(), new Class[]{View.OnClickListener.class}, new OnClickInvocationHandler(content,method));      //6.设置监听      view.setOnClickListener(listener);  }     } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {  e.printStackTrace();     } }    }}

OnClickInvocationHandler

public class OnClickInvocationHandler implements InvocationHandler {    private final Object content;//可以是Activity,fragment,dialog    private final Method method;    public OnClickInvocationHandler(Object content, Method method) { this.content = content; this.method = method;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (content != null) {     //这里的回调是 setOnClickListener的回调     //method 也就是start方法     this.method.invoke(content,args); } return null;    }}

动态代理用上了,但好像也没解决问题,只不过是换了个高级点的用法,屁用没有。
问题依旧存在,如下:

1.那就是如果你还要注册长按事件,viewpager的滑动事件,那是不是还得继续往文件写代码,违背了类的单一原则,也不好扩展,
2.你如何区分哪个控件需要长按,哪个不需要?按照下面的写法,所有的控件都会被自动注册长按事件。
留到下一章解决,haha

动态代理-事件注入(二)https://blog.csdn.net/wumeixinjiazu/article/details/122499788

代码地址:IOCDemo: 动态代理ioc注解https://gitee.com/small_insects/IOCDemo