一. 使用背景
如果没用过ViewBinding, 可以先去了解下. Android ViewBinding的使用
对于findViewById和OnClick,大部分时候, 我们使用ButterKnife就可以了,但是呢,谷歌后面出了DataBinding和Viewbinding来解决findViewById的问题,用了这两个以后,估计大家也不会使用ButterKnife. 那么问题来了,OnClick怎么处理呢? 直接手写吗? 所以就写了一个针对Onclick处理的小插件. 如下图:
解决的问题:
1. 每次都需要手动写重复的代码.
2. 在lib中,id无法用Switch(viewId)
二. 引用插件方式
File---settings---Plugins. 搜索OnClickMe
如果Android studio搜索不到插件?
点击File | Settings | Appearance & Behavior | System Settings | Updates 记住 Use secure connection(不要勾选),如果勾选就取消,然后重启
三. 使用方式
①. 和ButterKnife差不多,鼠标右键 选中布局(activity_main 或 ActivityMainBinding)---generate----OnClickMe.
②.项目首次使用, 需要勾选“生成解析类”,重新编译一下即可生成对应的类,生成的类在 src/java/liys/click下
//要在setContentView之后使用
OnClickUtils.init(Activity activity); //Activity中使用
OnClickUtils.init(Object target, View view); //Fragment或其它地方使用
//混淆, 保留R文件
-keep class **.R$* {
*;
}
-keepclasseswithmembers class * {
@liys.click.AClickStr ;
}
-keepclasseswithmembers class * {
@liys.click.AClick ;
}
四.关于性能问题
解析使用的是反射,原因有3个:
- 一般的App,一个页面能有多少个点击监听?用不用反射,我们人体是察觉不到有什么变化的.
- 手机硬件也在不断的升级,影响只会越来越小.
- 可以节约一些开发时间.
五.工具类源码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AClick {
@IdRes int[] value() default { View.NO_ID };
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AClickStr {
String[] value() default {""};
}
public class OnClickUtils {
public static void init(Activity target){
View sourceView = target.getWindow().getDecorView();
initClick(target, sourceView);
}
public static void init(Object target, View view){
initClick(target, view);
}
private static void initClick(@NonNull final Object target, @NonNull View source){
String packageName = source.getContext().getPackageName();
final Method[] methods = target.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
boolean hasAnno = methods[i].isAnnotationPresent(AClick.class);
if(hasAnno){
AClick aClick = methods[i].getAnnotation(AClick.class);
assert aClick != null;
int[] ids = aClick.value();
for (int j = 0; j < ids.length; j++) {
final int finalI = i;
source.findViewById(ids[j]).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
methods[finalI].invoke(target, v);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
boolean hasAnnoStr = methods[i].isAnnotationPresent(AClickStr.class);
if(hasAnnoStr){
AClickStr aClick = methods[i].getAnnotation(AClickStr.class);
final String[] ids = aClick.value();
for (int j = 0; j < ids.length; j++) {
final int finalI = i;
int id = 0;
try {
Class clazz = Class.forName(packageName+".R$id");
Field field = clazz.getDeclaredField(ids[j]);
id = (int)field.get(null);
} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
if(id==0){
continue;
}
final int finalJ = j;
source.findViewById(id).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
methods[finalI].invoke(target, v, ids[finalJ]);
}catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}