学以致用--注解加反射实现Butterknife的View注入功能

不知不觉更文挑战来到了第三天,今天来写一篇反射和注解的应用篇

对反射不熟悉的同学,请阅读 搞懂Java反射和JDK里的动态代理

对注解不熟悉的同学,请阅读 搞懂Java高级特性—注解

首先这篇文章,只是对注解和反射的一个应用对Butterknife不做过多的讨论,Butterknife早期实现的方式也是通过反射和注解实现的,但是大家都知道反射是会很耗费性能的,所以Butterknife换了方案,这个以后的文章会写

1、实现view注入的思路

我们在实现某个功能的时候,肯定得先梳理逻辑,不能需求拿来就开始写,这样写出来的代码不仅性能质量都不怎么好,还经常会出一些意向不到的bug,所以我们要养成一个习惯,先思考再写代码!

所谓的view注入功能,就是自动帮我们实现findViewById

如何区分我们要注入的View和其他属性?

自然而然,我们想到了我们的注解,我们给我们的View打一个标签,来标记这个是我们需要注入的View

如何获取注入的view信息,然后执行findViewById

这个就需要用到我们的反射,来获取了,对反射不熟悉的同学,上边有传送门

我们可以通过反射拿到Activity对象的所有属性,然后再根据属性上是否有我们定义的注解来区分那个是我们需要注入的View,也能通过注解来获取我们需要注入的ID,然后通过findViewById这个方法来获取view实例,然后再用反射将view实例赋值

2、代码具体实现

我们实现的标签(注解)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//作用于属性
public @interface InjectView {

    @IdRes int value ();
}

首先我们注解的作用域应该是在属性上,所以@Target(ElementType.FIELD),因为我们使用反射来实现的这个功能所以注解的生命周期用RUNTIME
具体注入的方法

public class InjectUtils {
    public static void injectView(Activity activity){
        Class<? extends Activity> activityClass=activity.getClass();

        //获得此类所有的成员
        Field[] declaareFields=activityClass.getDeclaredFields();
        for (Field declareField : declaareFields) {
            //判断属性是否被InjectView注解声明
            if(declareField.isAnnotationPresent(InjectView.class)){
                InjectView injectView=declareField.getAnnotation(InjectView.class);
                //获取注解中的id
                int viewId=injectView.value();
                View view=activity.findViewById(viewId);
                //反射设置属性的值
                declareField.setAccessible(true);//设置访问权限 如果是public 就可不设
                try {
                    declareField.set(activity,view);//讲view设置给属性
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

getFields获取所有修饰符为public的属性,包括父类
getDeclaredFields方法是获取此对象的所有属性,但是不包括父类
如果想获取父类的private 属性怎么办?可以先获取superClass然后再用getDeclaredFields获取父类的私有属性
最后是Activity的使用

public class MainActivity extends AppCompatActivity {
    @InjectView(R.id.tv_title)
    TextView tvTitle;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InjectUtils.injectView(this);
        tvTitle.setText("被遗忘的凉白开");
    }
}

运行效果:

1622710342(1).jpg

3、总结

单单就注解来讲,注解还是挺简单的,但是注解和其他技术结合,就会变的很有意思很好玩,也很复杂!比如字节码增强技术,也是注解和字节码技术的结合!所以我们用这么一个注入View的实例来巩固一下反射和注解!现在我用注解和反射实现了View的注入,大家也可以尝试一下用同样的方法实现对Intent传递数据之后的注入!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱码士赵Sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值