Android中为按钮绑定事件的有几种常见方式,你可以在布局文件中为按钮设置id,然后在MainActivity中通过findViewById方法获取按钮对象实例,再通过setOnClickListener为按钮绑定事件,如下所示:

//1.获取控件
btn = (Button)findViewById(R.id.button1);
//2.绑定事件
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
callPhone();
} });

你也可以在布局文件中直接为按钮设置onClick属性,然后在MainActivity中实现方法(实际应用中相较应用较少,本文主要以前一种方式为契机,故不再赘述基本语法格式)。

当一个应用中有很多按钮都需要绑定事件,甚至很多按钮需要绑定的事件具有一定的通用性的时候,我们可以参考一些流行的工具类,利用Java中的反射原理和注解,来写一个简单的工具类,帮助我们完成上述工作,让代码看起来更简洁,提高工作效率。

首先还是先简单介绍一下本文将用到的暴力反射和注解方面的一些知识吧。

反射机制,就是Java中任意一个类,可以通过获取其字节码的方式,将其属性、构造方法、方法和注解等等映射成Method、Constructor、Field、Annotation类,然后对其进行操作。所谓暴力反射是针对类中一些声明为private的成员,通过obj.setAccessible(true);的方式来强行使用私有成员。

Java中的注解Annotation,平时我们常见的一些jdk提供的注解相信大家一定不会陌生,比如@Override(提示重写父类方法,如果不能构成重写的话会报错);@Deprecated(抑制过时警告);@SuppressWarnings(抑制警告),简而言之,注解就是给JVM看的注释。本文将会用到自定义注解,大概写个小例子说明一下自定义注解的用法:

package com.yuki.vu;

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 MyInject { int value(); }

@interface就是注解类的标志性声明了(注意,类成员只能是以下几种:基本数据类型、Class类型、枚举类型

元注解:
@Retention:指定的注解作用范围
值:
RetentionPolicy.SOURCE  java源码范围可见
RetentionPolicy.CLASS .class字节码可见
RetentionPolicy.RUNTIME 运行的时候都可见
 
@Target:代表定义的注解修饰范围(属性,方法,类)
ElementType.TYPE:注解修饰类
ElementType.METHOD:注解修饰方法
ElementType.FILED:注解修饰属性

以上只是对反射和注解的简单介绍,详细使用还请另寻资料。接下来开始编写我们的小工具,代码如下:

MyViewUtils.java文件

package com.yuki.vu;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener; public class MyViewUtils { public static void inject(final Activity activity){
//反射属性
Field[] declaredFields = activity.getClass().getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
field.setAccessible(true);
MyInject annotation = field.getAnnotation(MyInject.class);
if (annotation!=null) {
int id = annotation.value();
View view = activity.findViewById(id);
try {
field.set(activity, view);
} catch (Exception e) {
e.printStackTrace();
}
}
} //反射方法
Method[] declaredMethods = activity.getClass().getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
final Method method = declaredMethods[i];
method.setAccessible(true);
MyClick annotation = method.getAnnotation(MyClick.class);
if (annotation!=null) {
int[] value = annotation.value();
for (int j : value) {
int id = j;
final View btn = activity.findViewById(id);
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
try {
method.invoke(activity, btn);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
} }
}

MyInject.java文件:

package com.yuki.vu;

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 MyInject { int value(); }

MyClick.java文件:

package com.yuki.vu;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyClick {
int[] value();
}

在掌握了反射和注解用法的基础上,看懂以上代码应该不难(代码有哪里不清楚的地方可以评论留言哈^.^),你可以将这三个文件的源文件直接导入工程,也可以把它们打包成一个jar文件,日后导入libs中使用,具体使用如下:

package com.yuki.vu;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends Activity { @MyInject(R.id.tv)
private TextView tv;
@MyInject(R.id.et)
private EditText et;
@MyInject(R.id.btn1)
private Button btn1;
@MyInject(R.id.btn2)
private Button btn2;
@MyInject(R.id.btn3)
private Button btn3; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); MyViewUtils.inject(this);
Log.d("tag", ""+btn1.getText());
} @MyClick({R.id.btn1, R.id.btn2, R.id.btn3})
public void submit(View view){
Toast.makeText(this, ((Button)view).getText(), Toast.LENGTH_SHORT).show();
}
}

以上就是MainActivity的代码了。可以看到,在使用工具类的情况下,首先通过@MyInject注解获取每个带有id的按钮控件,再通过MyClick的方法为每个按钮绑定事件,最后在onCreate方法中通过一句MyViewUtils.inject(this)来完成按钮与事件的绑定,至此大功告成~撒花

其实以上内容也是从著名的工具类xUtils中参考而来,你可以在github等网站找到这些强大的工具类的源码以及详细的使用说明,故本文只为我们自己编写工具类做一个抛砖引玉的小例子,仅供参考,欢迎交流~

Android自定义工具类获取按钮并绑定事件(利用暴力反射和注解)的更多相关文章

  1. Android普通工具类获取Context

    在普通工具类中定义一个构造方法,类成员context,用于接收传过来的context 在activity中定义: 将context传过去. 在工具类中也可以使用SharePreferences,get ...

  2. WzwJDBC 自定义工具类(获取连接,释放资源)

    package wzwUtil;import java.io.IOException;import java.io.InputStream;import java.sql.*;import java. ...

  3. (转载)android 一些工具类汇总

    android 一些工具类汇总 作者:曾田生z 字体:[增加 减小] 类型:转载 时间:2016-08-14我要评论 本文给大家汇总介绍了一些常用的Android工具类,非常的简单实用,有需要的小伙伴 ...

  4. Android 常见工具类封装

    1,MD5工具类: public class MD5Util { public final static String MD5(String s) { char hexDigits[] = { '0' ...

  5. 53. Android常用工具类

    主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java.目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils.Prefer ...

  6. 【转】Android常用工具类

    主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java. 目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils.Prefe ...

  7. ThinkPHP3验证码、文件上传、缩略图、分页(自定义工具类、session和cookie)

    验证码 TP框架中自带了验证码类 位置:Think/verify.class.php 在LoginController控制器中创建生存验证码的方法 login.html登陆模板中 在LoginCont ...

  8. 使用java的Calendar工具类获取到本月的第一天起始时间和最后一天结束时间。

    1.使用java的Calendar工具类获取到本月的第一天起始时间和最后一天结束时间. package com.fline.aic.utils; import java.text.DateFormat ...

  9. Spring普通类/工具类获取并调用Spring service对象的方法

    参考<Spring普通类获取并调用Spring service方法>,网址:https://blog.csdn.net/jiayi_0803/article/details/6892455 ...

随机推荐

  1. java学习笔记day02

    1.如何定义一个功能,并通过函数(方法)体现出来呢?  1)明确改功能运算后的结果.确定函数的返回值类型.  2)明确在实现该功能的过程中是否有未知内容参与运算.确定参数列表. 2.函数重载:在同一个 ...

  2. @page指令 validateRequest的作用

    在 Web 应用程序中,要阻止依赖于恶意输入字符串的黑客攻击,约束和验证用户输入是必不可少的.跨站点脚本攻击就是此类攻击的一个示例.其他类型的恶意数据或不需 要的数据可以通过各种形式的输入在请求中传入 ...

  3. 疯狂Android第二章:Adapter以及部分控件使用

    第二章 重点:1.理解View以及各种布局的优缺点,适用场景. 2.熟练掌握adapter原理与用法. 3.熟悉其它控件的基本使用方法. /////////////////////////////// ...

  4. iframe 重新加载闪过白块问题

    在使用iframe时,iframe背景为白块,刷新时也会闪过白块.如果刷新时间长,就会一直出现白块,让人很烦恼,通过网上搜资料,测试最终解决方法如下所示,注意主要针对IE浏览器测试. 一.iframe ...

  5. C# 获得两日期之间所有月份(包括跨年)

    前台: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3. ...

  6. sql server保留小数解决方法

    在数据库中,我们有时会用到小数,怎样在数据库中转化小数呢,下面是一些常用的方法. 1.使用Round(字段名/数字,小数保留位数)方法,如下所示: select Round(3.333,2) 结果如下 ...

  7. [转]如何正确清理C盘

    转自微软的Answers网站. 以下是推荐使用的方法,安全且不会误删有用的系统文件 1.尽量不要在C盘安装应用软件,在软件安装时,一般可以手动指定安装路径,您可以将软件指定安装到其他盘符. 在使用它们 ...

  8. windows系统下搭建Python开发环境

    1.首先下载最新的Python http://www.python.org/download/,我下载的是最新的Python3.5.1 2.下载完成之后开始安装,安装就比较简单了,一路下一步. 3.安 ...

  9. What is SignalR and Why Should I Use It?

    原文地址: What is SignalR and why should I use it? When I first heard about SignalR, I was not sure what ...

  10. ffmpeg推rtmp流到crtmpserver直播

    1. 项目需要使用ffmpeg推rtmp流至crtmpserver,然后直播./usr/bin/ffmpeg -re -loop 1 -i tmp/234.jpg -r 10 -f flv rtmp: ...