0. 环境:
电脑:Windows10
Android Studio: 2024.3.2
编程语言: Java
(重要提示,安卓新版本不再支持下面的代码。以下仅提供思路)
如果需要使用findViewById的工具,推荐使用ButterKnife
如果是需要优雅简单使用框架,可以使用MVVM框架,Android官方推荐的ViewBinding
1. 创建工具类,用于实现findViewById
我这里直接创建了一个InjectUtils.java文件,用于实现功能
直接上代码:
public class InjectUtils {
public static void injectView(Activity activity) {
Class<? extends Activity> clz = activity.getClass();
// 获取所有成员
Field[] declaredFields = clz.getSuperclass().getDeclaredFields();
// 遍历
for (Field field : declaredFields) {
// 如果为注解InjectView
if (field.isAnnotationPresent(InjectView.class)) {
// 获取该成员的InjectView注解
InjectView injectView = field.getAnnotation(InjectView.class);
// 获取该注解的value。也就是我们在InjectView中定义的value属性
int id = injectView.value();
View view = activity.findViewById(id);
// 设置访问权限,允许操作private。如果是public, 可以不用加这行代码
field.setAccessible(true);
try {
// 通过反射 设置属性值
field.set(activity, view);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
2. 获取成员的方法
方法名 | 含义 |
getField(String name) |
获得自己和父类的成员,只能是public |
getFields() |
getField 的数组 |
getDeclaredField() |
只能获得自己的成员,不包括父类,所有作用域 |
getDeclaredFields() |
getDeclaredField 的数组 |
如果需要获取父类的private,可以参考伪代码:
try {
Class<? extends Activity> clz = activity.getClass();
// 先获取父类class 再获取成员名为 field的成员
clz.getSuperclass().getDeclaredField("field");
// 同理,先获取父类class 再获取所有成员
clz.getSuperclass().getDeclaredFields();
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
3. 写在最后
Android已经更新R.id.xxxx资源的生成方法,虽然还有final,但是移除了static. 导致资源id为动态生成。
如果你写烦了 findViewById,可以使用成熟的工具、框架、注解等方法来实现。
工具:推荐使用ButterKnife
框架,可以使用MVVM框架,Android官方推荐的ViewBinding