【安卓笔记】注解反射,优雅的findViewById

发布于:2025-07-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

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


网站公告

今日签到

点亮在社区的每一天
去签到