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. c# 图片简单模糊 非高斯模糊

    /// <summary>        /// 图像模糊化        /// </summary>        /// <param name="bit ...

  2. javax inect

    Spring 3 and JSR-330 @Inject and @Named example By mkyong | September 16, 2012 | Viewed : 86,399 tim ...

  3. C#基础学习心得(二)

    索引器 class Program { static void Main(string[] args) { Employee e1 = new Employee(); e1[0] = "三& ...

  4. mono for android 学习资料

    http://www.cnblogs.com/Hua-Min/tag/Android/

  5. B - Numbers That Count

    Description        "Kronecker's Knumbers" is a little company that manufactures plastic di ...

  6. Notepad++编译c++时使用的代码

    cmd /c "g++ -o $(CURRENT_DIRECTORY)\$(NAME_PART).exe $(FULL_CURRENT_PATH)" 出现控制台.  NppExec ...

  7. 给WebApp加一个“壳”,实现Andriod系统添加到桌面

    IOS系统的Safari浏览器有一个“添加到桌面”的功能,能在手机桌面上为你的Webapp添加一个快捷方式,其外观和Native App看起来一样. 这个功能对Webapp来说太有用了,它能让用户像“ ...

  8. Python之路第六天,基础(7)-正则表达式(re)

    Python RE模块(正则表达式) 就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成 ...

  9. Python爬虫实战(4):豆瓣小组话题数据采集—动态网页

    1, 引言 注释:上一篇<Python爬虫实战(3):安居客房产经纪人信息采集>,访问的网页是静态网页,有朋友模仿那个实战来采集动态加载豆瓣小组的网页,结果不成功.本篇是针对动态网页的数据 ...

  10. Python Challenge 过关心得(0)

    最近开始用Openerp进行开发,在python语言本身上并没有什么太大的进展,于是决定利用空闲时间做一点python练习. 最终找到了这款叫做Python Challenge(http://www. ...