实现注入view,简单案例剖析butterknife原理

ButterKnife注入框架我相信大家都用过至少听过吧,它的出现简直是android开发人员的一大福利,彻底解放了无止境的findViewById,而是通过优雅的注解来实现view的赋值,如果你真没听过那我在这里只能贴上一张github的截图,自己好好反思吧~

butterKnife地址

这里写图片描述

1w5的star你还有什么不学的理由!!!

好的,今天我们不说butterfnife怎么用,而是仿照框架中的实现原理,用最简单的例子自己来实现view的注入!

1、编写自定义注解类

既然是注入的形式对view赋值,那么当然少不了注解,我们最常用的莫过于setContentView和findViewById,我们先来定义这两个注解(注释中顺便帮同学们补一些注解的知识):

setContentView

/**
 * @Target描述注解的使用范围
 * 1.CONSTRUCTOR:用于描述构造器
  2.FIELD:用于描述域
  3.LOCAL_VARIABLE:用于描述局部变量
  4.METHOD:用于描述方法
  5.PACKAGE:用于描述包
  6.PARAMETER:用于描述参数
  7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
 */
@Target(ElementType.TYPE)
/**
 *  @Retention 该Annotation被保留的时间长短
 *   1.SOURCE:在源文件中有效(即源文件保留)
   2.CLASS:在class文件中有效(即class保留)
   3.RUNTIME:在运行时有效(即运行时保留)
 */
@Retention(RetentionPolicy.CLASS)
public @interface SetContent {
    int value() default -1;
}

findViewById

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface BindView {
    int value();
}

注解定义好之后,我们的目标是在activity中这样使用对不对

@SetContent(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
    @BindView(R.id.tv_text)
    private TextView textView;
}

这是我们需要一个解析器。

2、编写注解解析器,为这些view赋值

/**
 * Created by admin on 2017/4/2.
 * 注入解析器
 * 单例
 */
public class MyAnnotationInject {
    private static MyAnnotationInject INSTANCE;
    private List<Object> mInjectObjs = new ArrayList<Object>();

    public static MyAnnotationInject init() {
        if (INSTANCE == null) {
            INSTANCE = new MyAnnotationInject();
        }
        return INSTANCE;
    }

    /**
     * 注册需要注入的类对象
     * @param injectObj
     */
    public void regist(@NonNull Object injectObj) {
        if(mInjectObjs.contains(injectObj)){
            return;
        }
        if (injectObj instanceof Activity) {
            Activity activity = (Activity) injectObj;
            //拿到注入的class对象
            Class<Activity> clz = (Class<Activity>) activity.getClass();
            try {
                injectContentView(activity, clz);
                injectView(activity, clz);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        mInjectObjs.add(injectObj);
    }

    /**
     * 注入view
     */
    private void injectView(Activity activity, Class<Activity> clz) throws IllegalAccessException {
        //获得所有的属性,包括public、protected、private
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            //遍历所有属性,找到标有Bindview注解的属性
            if (field.isAnnotationPresent(BindView.class)) {
                //拿到BindView注解的值
                BindView annotation = field.getAnnotation(BindView.class);
                int viewId = annotation.value();
                //如果是私有属性,修改属性赋值之前必须加可修改权限
                field.setAccessible(true);
                //给属性重新赋值,参数1:要修改的属性的对象 , 参数2 : 新值
                field.set(activity, activity.findViewById(viewId));
            }
        }
    }

    /**
     * 注入activity布局
     */
    private void injectContentView(Activity activity, Class<Activity> clz) {
        if (clz.isAnnotationPresent(SetContent.class)) {
            //拿到SetContent注解的值
            SetContent annotation = clz.getAnnotation(SetContent.class);
            int resId = annotation.value();
            if (resId != -1) {
                activity.setContentView(resId);
            }
        }
    }

    /**
     * 注销需要注入的类对象
     * @param injectObj
     */
    public void unRegist(Object injectObj) {
        if (mInjectObjs.contains(injectObj))
            mInjectObjs.remove(injectObj);
    }
}

3、Activity中使用我们的注解来代替findViewById

@SetContent(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
    @BindView(R.id.tv_text)
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyAnnotationInject.init().regist(this);
        textView.setText("通过注解注入view成功!");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        MyAnnotationInject.init().unRegist(this);
    }
}

我们看一下效果:
这里写图片描述

当然我这只是butterknife中冰山一角,如果想要具体学习整个框架可以去学习butterknife的源码~
butterKnife地址,点我

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值