你可以 随便找个人依靠 那么寒冬后 炎夏前 谁会给你春一样的爱恋 日落后 最美的 时光已溜走——《三十岁的女人》
上篇文章《java反射机制和自定义注解原理分析和实例》已经介绍了java的反射机制和自定义注解的基本原理和简单实例。本篇文章模仿android的框架xUtils的ViewUtils模块,完全注解方式就可以进行UI绑定和事件绑定,无需findViewById和setClickListener等。
(1)创建自定义注解,代表绑定控件,接收控件的id值,ViewInject.class
package com.chunsoft.viewbind;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Developer:chunsoft on 2017/3/3 12:25
* Email:[email protected]
* Content:findViewById
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
(2)创建自定义注解,代表单击事件绑定,接收控件的id值,onClick.class
package com.chunsoft.viewbind;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Developer:chunsoft on 2017/3/3 12:26
* Email:[email protected]
* Content:单击事件绑定
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface onClick {
int value();
}
(3)实现具体的控件绑定和单击事件绑定,步骤详细,ViewUtils.class
package com.chunsoft.viewbind;
import android.app.Activity;
import android.view.View;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Developer:chunsoft on 2017/3/3 12:27
* Email:[email protected]
* Content:实现具体的绑定方法
*/
public class ViewUtils{
public static void inject(Activity activity) {
//绑定控件
bindView(activity);
//绑定事件
bindOnClick(activity);
}
private static void bindOnClick(final Activity activity) {
/**
* 1.获取Activity的字节码
*/
Class clazz = activity.getClass();
/**
* 2.获取该字节码的所有方法
*/
Method[] declaredMethods = clazz.getDeclaredMethods();
/**
* 3.遍历方法,找出方法上声明为onClick的方法
*/
for (final Method method:declaredMethods) {
/**
* 4.获取字段上面指定的注解
*/
onClick mOnClick = method.getAnnotation(onClick.class);
if (mOnClick != null) {
/**
* 5.获取当前注解值
*/
int resId = mOnClick.value();
/**
* 6.通过调用Activity的findViewById方法,获取当前id为resId的控件
*/
final View view = activity.findViewById(resId);
/**
* 7.给当前的View绑定点击监听事件
*/
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 8.通过反射调用当前的用户方法
*/
method.setAccessible(true); //暴力反射
try {
method.invoke(activity,view); //不能抛出异常,父类没有抛出异常,子类也不能抛出异常
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
private static void bindView(Activity activity) {
/**
* 1.获取Activity的字节码
*/
Class clazz = activity.getClass();
/**
* 2.获取该字节码的所有的Field
*/
Field[] declaredFields = clazz.getDeclaredFields();
/**
* 3.遍历字段,判断哪些是我们想要的字段(只有添加ViewInject注解的字段)
*/
for (Field field:declaredFields) {
//获取字段上面指定的注解
ViewInject viewInject = field.getAnnotation(ViewInject.class);
if (viewInject != null) {
/**
* 4.获取当前注解值
*/
int resId = viewInject.value();
/**
* 5.通过调用Activity的findViewById方法,获取当前id为resId的控件
*/
View view = activity.findViewById(resId);
/**
* 6.通过依赖注入,将当前View设置为=给当前的Field
*/
// 暴力反射
field.setAccessible(true);
try {
field.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}else {
}
}
}
}
(4)在Activity中测试,MainActivity.class
package com.chunsoft.viewbind;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.tv1)
private TextView tv1;
@ViewInject(R.id.tv2)
private TextView tv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewUtils.inject(this);
Toast.makeText(this,tv1.getText().toString(),Toast.LENGTH_SHORT).show();
Log.d("测试ViewInject",tv1.getText().toString()+tv2.getText().toString());
}
@onClick(R.id.btn1)
private void Click(View view) {
Toast.makeText(this,"点击成功",Toast.LENGTH_SHORT).show();
}
}
我们通过上面的代码通过注解方式和反射就实现了一个简单的UI绑定和事件绑定。下面我们将框架打包成jar文件。
框架写好后,通过Android Studio 导出框架,导出jar包。
(1)修改build.gradle文件
在Android Studio中会显示多个build.gradle文件,如果你想要将整个项目导出成jar包,就找到对应项目名目录下的build.gradle文件,对其进行修改。有如下几个地方需要修改:
将最前面的apply plugin: 'com.android.application' 修改为apply plugin: 'com.android.library'
将defaultConfig修改为:
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
}
SDK的版本可以根据自己的版本来改
在最后加上:
task deleteOldJar(type: Delete) {
delete 'build/outputs/ViewUtils.jar'
}
task exportJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('build/libs/')
include('classes.jar')
rename ('classes.jar', 'ViewUtils.jar')
}
exportJar.dependsOn(deleteOldJar, build)
导出的路径,这个可以自定义,rename里的ViewUtils.jar是要导出的jar包的名字,也是自定义的。
这些修改完后就是一下可视化操作了。
(2)可视化操作
再打开app->Tasks->other->exportJar
然后双击exportJar就可以了,在设置的路径下可以找到对应的jar文件,ViewUtils.jar。框架比较简单,大家最好自己实现下,需要源码请留言。