Android注解解析,注解用法,仿xUtils用注解初始化控件、点击事件(二)
2016-09-08 18:16
489 查看
这篇相对于之前的有点难度,需要大家熟练Java反射和Proxy代理流程才能看的容易些,因为这两块不是这篇文章的重点,不懂的可以网上查一下,了解个大概,就可以了。
首先,我先贴出MainActivity的点击事件代码,因为比较简单:
不多说,就是一个方法而已,当然,@IOnlick我们还没有写,再看@IOnlick:
上面有足够的注解,我就不多说了,大概的流程就是先获取到@IOnclick,再通过@IOnclick获取上面的@BaseEvent注解,下面看@BaseEvent:
这个相对简单,上面也都有注解,看一下就懂了,接下来是最关键的,我先讲一下流程,正常的设置点击监听事件的流程如下图(电脑上没有多少软件,临时那PS滑的,大家凑合看吧):
上面的图很简单,我们都能看懂,而我们现在要做的就是改变一下,见下图:
上面的图看明白后,接下来就很简单了没错,我们需要做的就是把onClick方法拦截下来,然后执行我们自己的方法。
贴InjectUtils里最后一个方法的代码 OnClick:
注解已经很详细,拦截的地方也已经标明,只要原理明白了,理解上去不难,接下来是InjectInvocationHandler的代码:
OK,相信这些代码对大家来说更简单,注解很全,接下来我们运行程序,并点击登录按钮:
下面弹出了吐司,证明代码已经生效!喜欢的朋友们留个言吧~~~~~~~~~
首先,我先贴出MainActivity的点击事件代码,因为比较简单:
@IOnClick({R.id.btn_login, R.id.btn_login}) public void showToast(View view) { switch (view.getId()) { case R.id.btn_login: Toast.makeText(this, "登录", Toast.LENGTH_SHORT).show(); break; case R.id.btn_logoff: Toast.makeText(this, "注销", Toast.LENGTH_SHORT).show(); break; default: break; } }
不多说,就是一个方法而已,当然,@IOnlick我们还没有写,再看@IOnlick:
//btn_login.setOnClickListener(new View.OnClickListener() { //setListener listenerType // @Override // public void onClick(View v) { // listenerCallback // } //}); @Target(ElementType.METHOD) //注解应用于其他注解上 @Retention(RetentionPolicy.RUNTIME) //这个注解需要注意,对应的参数在上面注解的 btn_login 点击事件里对应找即可 @BaseEvent(setListener = "setOnClickListener",//setOnClickListener为View.setOnClickListener listenerType = View.OnClickListener.class,//监听的类型为点击事件 listenerCallback = "onClick")//这个onClick回调,即为setOnClickListener后回调的onClick public @interface IOnClick { int[] value();//因为一个方法可能与多个控件绑定 }
上面有足够的注解,我就不多说了,大概的流程就是先获取到@IOnclick,再通过@IOnclick获取上面的@BaseEvent注解,下面看@BaseEvent:
@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface BaseEvent { String setListener();//设置监听方法名 Class listenerType();//监听类型 String listenerCallback();//监听回调方法名 }
这个相对简单,上面也都有注解,看一下就懂了,接下来是最关键的,我先讲一下流程,正常的设置点击监听事件的流程如下图(电脑上没有多少软件,临时那PS滑的,大家凑合看吧):
上面的图很简单,我们都能看懂,而我们现在要做的就是改变一下,见下图:
上面的图看明白后,接下来就很简单了没错,我们需要做的就是把onClick方法拦截下来,然后执行我们自己的方法。
贴InjectUtils里最后一个方法的代码 OnClick:
private static void 4000 OnClick(Activity activity) { // 获取MainActivity Class<? extends Activity> clazz = activity.getClass(); // 获取MainActivity中所有方法 Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { // 获取方法上对应的@IOnclick的注解 Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations) { // 通过annotationType获取注解@BaseEvent Class<? extends Annotation> annotationType = annotation.annotationType(); //需要判断是否为null if (annotationType != null) { // 获取@IOnclick注解上的BaseEvent注解 BaseEvent baseEvent = annotationType.getAnnotation(BaseEvent.class); //需要判断是否为null,因为有的注解没有@BaseEvent if (baseEvent != null) { // 获取@BaseEvent的三个value String callback = baseEvent.listenerCallback(); Class type = baseEvent.listenerType(); String setListener = baseEvent.setListener(); try { // 通过反射获取方法,@IOnclick里的int[] value()不需要传参,所以参数省略 Method declaredMethod = annotationType.getDeclaredMethod("value"); // 调用方法,获取到@IOnclick的value,即两个button的id,参数省略 int[] valuesIds = (int[]) declaredMethod.invoke(annotation); // 这个类稍后会给出代码,目的是拦截方法 InjectInvocationHandler handler = new InjectInvocationHandler(activity); // 添加到拦截列表 handler.add(callback, method); // 得到监听的代理对象 Proxy proxy = (Proxy) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler); // 遍历所有button的id for (int valuesId : valuesIds) { View view = activity.findViewById(valuesId); // 通过反射获取方法 Method listener = view.getClass().getMethod(setListener, type); // 执行方法 listener.invoke(view, proxy); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } }
注解已经很详细,拦截的地方也已经标明,只要原理明白了,理解上去不难,接下来是InjectInvocationHandler的代码:
public class InjectInvocationHandler implements InvocationHandler { // 拦截的方法名列表 private Map<String, Method> map = new HashMap<>(); // 在这里实际上是MainActivity private Object target; public InjectInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (target != null) { // 获取方法名 String name = method.getName(); Method m = map.get(name); if (m != null) {//如果不存在与拦截列表,就执行 return m.invoke(target, args); } } return null; } /** * 向拦截列表里添加拦截的方法 */ public void add(String name, Method method) { map.put(name, method); } }
OK,相信这些代码对大家来说更简单,注解很全,接下来我们运行程序,并点击登录按钮:
下面弹出了吐司,证明代码已经生效!喜欢的朋友们留个言吧~~~~~~~~~
相关文章推荐
- 去除烦人的This Handler class should be static or leaks might occur
- Android注解解析,注解用法,仿xUtils用注解初始化控件、点击事件(一)
- android 加载大图的原理和实现
- Android开发艺术探索--第二章IPC机制(3)之Android中的IPC方式
- android 开发之坑系列_实体序列化问题
- Android Studio提交库至Bintray jCenter从入门到放弃
- Android Studio提交库至Bintray jCenter从入门到放弃
- android屏幕监听,手机是否处于锁屏状态,在锁屏之上弹出Toast.makeText消息
- Android 百度地图打包后获取不到地址问题
- [Android]之一:Android系统下载管理DownloadManager
- AsyncTask 工作原理(下)
- android launcher开发(6) Launcher暂停,停止,销毁
- Android中的ViewPager在更新内容的时候报java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0异常
- android filter
- android 4.4删除短信
- Android draw9patch 图片制作与使用详解
- Android 系统信息的获取
- 【Android】提升用户体验,ListView显示加载中动画及空数据视图
- 隐藏android系统的状态栏和导航栏
- JNI详解(一)