Android自定义工具类获取按钮并绑定事件(利用暴力反射和注解)
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自定义工具类获取按钮并绑定事件(利用暴力反射和注解)的更多相关文章
- Android普通工具类获取Context
在普通工具类中定义一个构造方法,类成员context,用于接收传过来的context 在activity中定义: 将context传过去. 在工具类中也可以使用SharePreferences,get ...
- WzwJDBC 自定义工具类(获取连接,释放资源)
package wzwUtil;import java.io.IOException;import java.io.InputStream;import java.sql.*;import java. ...
- (转载)android 一些工具类汇总
android 一些工具类汇总 作者:曾田生z 字体:[增加 减小] 类型:转载 时间:2016-08-14我要评论 本文给大家汇总介绍了一些常用的Android工具类,非常的简单实用,有需要的小伙伴 ...
- Android 常见工具类封装
1,MD5工具类: public class MD5Util { public final static String MD5(String s) { char hexDigits[] = { '0' ...
- 53. Android常用工具类
主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java.目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils.Prefer ...
- 【转】Android常用工具类
主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java. 目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils.Prefe ...
- ThinkPHP3验证码、文件上传、缩略图、分页(自定义工具类、session和cookie)
验证码 TP框架中自带了验证码类 位置:Think/verify.class.php 在LoginController控制器中创建生存验证码的方法 login.html登陆模板中 在LoginCont ...
- 使用java的Calendar工具类获取到本月的第一天起始时间和最后一天结束时间。
1.使用java的Calendar工具类获取到本月的第一天起始时间和最后一天结束时间. package com.fline.aic.utils; import java.text.DateFormat ...
- Spring普通类/工具类获取并调用Spring service对象的方法
参考<Spring普通类获取并调用Spring service方法>,网址:https://blog.csdn.net/jiayi_0803/article/details/6892455 ...
随机推荐
- Linux以及Android开发中的小技巧和长繁命令记录收集
不断更新收集中.... 201407161654 ssh以nx_guest的身份登录到172.24.221.137,然后在172.24.221.137与172.24.61.252的8080port建立 ...
- C# 零散笔记
关于控件 控件实质就是一个类 属性中的Name就是它实例后的变量名 属性中的其他东西就是类中的变量或函数 例如: 可以直接通过Name.BackColor=Color.Yellow; 来直接操作控件的 ...
- DropDownList 绑定数据后 插入一条不属于表中的数据
ddlFGiftId.DataSource = dtGift; ddlFGiftId.DataTextField = "FGiftName"; ddlFGiftId.DataVal ...
- git使用经验
一直想写一点关于git的文章,但是平时太懒了,没有写,现在写些经验这里,方便以后自己忘记了.
- 今天进行了一次IOS面试,分享一下面试结果
IOS开发工程师岗位职责:1.负责移动产品IOS版客户端软件开发:2.可根据需求独立完成客户端软件的设计和开发;3.日常工作包括手机软件系统开发.单元测试.维护以及文档编写:不定期的公司内部培训.任职 ...
- poj-2403-cup
题目描述 The WHU ACM Team has a big cup, with which every member drinks water. Now, we know the volume o ...
- override和new的区别
override 1. override是派生类用来重写基类中方法的: 2. override不能重写非虚方法和静态方法: 3. override只能重写用virtual.abstract.overr ...
- JSP 基础之 JSTL <c:forEach>用法
在JSP的开发中,迭代是经常要使用到的操作.例如,逐行的显示查询的结果等.在早期的JSP中,通常使用Scriptlets来实现Iterator或者Enumeration对象的迭代输出.现在,通过JST ...
- const参数,const返回值与const函数
在C++程序中,经常用const 来限制对一个对象的操作,例如,将一个变量定义为const 的: const int n=3; 则这个变量的值不能被修改,即不能对变量赋值. const 这个关键字 ...
- 从汇编看c++多重继承中this指针的变化
先来看一下下面的c++源码: #include <iostream> using namespace std; class X { public: virtual void print1( ...