反射+注解完美解决Android繁琐的byId和click

Android小白,你还在使用findViewById吗?还在setOnClickListener等等。如果你用过butterknife的话,是不是觉得非常方便,有木有?那么问题来了,为啥别人可以写,我们就不能写?so,今天给大家带来自己实现butterknife的功能。
1.首先定义注解

/**
 * Created by yzz on 2017/3/22 0022.
 */
//作用域
@Target({ElementType.FIELD,ElementType.METHOD})
//生命周期
@Retention(RetentionPolicy.RUNTIME)
public @interface YzzAnnotation {
    public int id()default -1;
    public boolean click()default false;
}

该注解作用范围是字段和方法,生命周期在运行时有效(要想注解+反射就要保证注解的Retention为RetentionPolicy.RUNTIME)。有两个字段,分别为id和click分别来表示View的id和是否设置点击的监听。

2.通过反射技术初始化有该注解的字段
(1)初始化

//采用了泛型,灵活性更强
 public void bind(T t) {
         //软引用防止Context的内存泄漏
        softReference = new SoftReference<>(t);
        if (t == null) return;
        if (t instanceof ViewGroup || t instanceof Activity || t instanceof Fragment) {
            reflect();
        }
    }

(2)通过反射获得Activity或者Fragment或者ViewGroup的字段

/**
     * 反射获取字段
     */
    private void reflect() {
    //获得绑定的实体
        T t = softReference.get();
        if (t == null) {
            throw new RuntimeException("null entity");
        }
        //获得class
        aClass = t.getClass();
        try {
            //初始化private的字段
            init(aClass.getDeclaredFields());
            //初始化非private的字段
            init(aClass.getFields());
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("========", "=========" + e.toString());
        }
    }

(3)为字段设置id和点击事件

 /**
     * 为字段设置id
     *
     * @param f
     * @throws Exception
     */
    public void init(Field[] f) throws Exception {
        if (f == null) return;
        for (Field field : f) {
        //判断字段是否有我们自己的注解,有就init
            if (field.isAnnotationPresent(YzzAnnotation.class)) {
                //这里要获得访问权限
                field.setAccessible(true);
                YzzAnnotation yzz = field.getAnnotation(YzzAnnotation.class);
                //获取findViewById()
                Method m = aClass.getMethod("findViewById", int.class);
                //调用findViewById()返回Object 
                Object ob = m.invoke(softReference.get(), yzz.id());
                //初始化字段(所属的对象,值)
                field.set(softReference.get(), ob);
                //设置监听
                //判断绑定的该类是否实现了View.OnClickListener接口
                Class<?> inter[] = aClass.getInterfaces();
                for (Class<?> c:inter){
                    if (c.getName().equals(View.OnClickListener.class.getName())){
                        if (yzz.click()) {
                        //得到setOnclickListener()方法
                            Method setOnclick = field.getType().getMethod("setOnClickListener",View.OnClickListener.class);
//调用该方法,为字段设置监听                            setOnclick.invoke(field.get(softReference.get()),softReference.get());
                        }
                    }
                }
            }
        }
    }

(4)调用(步骤异常的简单)

//id,click两个属性
@YzzAnnotation(id = R.id.button, click = true)
//支持私有字段(butterknife不支持哦)
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //得到绑定帮助类
        YzzAnn<MainActivity> yzzAnn = new YzzAnn<>();
       //绑定
        yzzAnn.bind(this);
        //此时的button!=null了,哈哈
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(getApplicationContext(), "click", Toast.LENGTH_LONG).show();
         button.setText("yzz--coding--!");
    }

好了看看效果,是不是很有意思呢?该帮助类还应该支持是普通的类,x.bind(this,View)这种形式的,其实都差不多。下次有机会再补充。github访问源码
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值