android的依赖注入

 这几年针对Android推出了不少View注入框架,例如ButterKnife。我们首先来了解一下使用这些框架有什么好处,其实好处很明显:它可以减少大量的findViewById以及setOnClickListener代码,简化了代码,让我们的代码看起来条理更清晰,可读性变强。

     可能大多数对于这一类框架,都只是停留在用的阶段,但是作为一个程序员,我们有必要去了解它是如何实现的。其实它的原理也没有多复杂,用到了Java中反射和注解的相关知识,所以对反射和注解了解不多的朋友可以先找一下相关资料了解一下。

关于注解,我在上一篇文章中介绍过

今天的任务呢就是教大家如何一步一步简单的实现一个类似 ButterKnife的依赖注入的效果:

第一步:我们需要自定义注解,如下:

//用于初始化view的

[java]  view plain  copy
  1. @Target(ElementType.FIELD)  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface BindView {  
  4.     int value() default 0;  
  5. }  
//用于绑定点击事件的

[java]  view plain  copy
  1. @Target(ElementType.METHOD)  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface BindClick {  
  4.     int value() default 0;  
  5. }  
从上面的Target里面的值我们可以知道,这两个注解一个是作用于属性,一个是作用于方法的。这里提醒一下 如果如果只有一个参数成员,最好把参数名称设为value,这里可以补一句因为使用该注解时,value作为key可省略,在使用的时候比较方便。

第二步:设置注解

[java]  view plain  copy
  1. @BindView(R.id.button)  
  2. private Button mButton;  
  3. @BindView(R.id.textview)  
  4. private TextView mTextView;  

[java]  view plain  copy
  1. @BindClick(R.id.button)  
  2. private void onButtonClick(){  
  3.     Toast.makeText(this,"Button被点击了",Toast.LENGTH_SHORT).show();  
  4. }  
  5. @BindClick(R.id.textview)  
  6. private void onTextViewClick(){  
  7.     Toast.makeText(this,"TextView被点击了",Toast.LENGTH_SHORT).show();  
  8. }  
第三步:获取注解,进行处理

[java]  view plain  copy
  1. public class InjectUtils {  
  2. /**
     *注入视图
     */
    public static void initView(Activity injectedActivity){
        initView(injectedActivity,injectedActivity.getWindow().getDecorView());
    }
    /**
     *注入视图
     */
    public static void initView(YYBaseViewController injectedViewController){
        initView(injectedViewController,injectedViewController.getView());
    }
    /**
     *注入视图
     */
    public static void initView(Object injectedSource,View sourceView){
        Field[] fields = injectedSource.getClass().getDeclaredFields();
        if(isNotNull(fields) && fields.length>0){
            for(Field field : fields){
                YYInjectView viewInject = field.getAnnotation(YYInjectView.class);
                if(isNotNull(viewInject)){
                    int viewId = viewInject.id();
                    try {
                        field.setAccessible(true);
                        if(field.get(injectedSource)!= null ){
                            //如果有值就屏蔽,例如float,int等类型
                            continue;
                        }
                        field.set(injectedSource,sourceView.findViewById(viewId));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

  3.     public static void inject(final Activity activity) {  
  4.         //遍历属性,对设置注解的view进行初始化  
  5.         Class<Activity> activityClass= (Class<Activity>) activity.getClass();  
  6.         Field fields[]=activityClass.getDeclaredFields();  
  7.         for(Field field:fields){  
  8.             if(field.isAnnotationPresent(BindView.class)){  
  9.                 int viewId=field.getAnnotation(BindView.class).value();  
  10.                 View view=activity.findViewById(viewId);  
  11.                 try {  
  12.                     //这一行代码是必须的,否则直接调用set方法不生效  
  13.                     field.setAccessible(true);  
  14.                     field.set(activity,view);  
  15.                 } catch (IllegalAccessException e) {  
  16.                     e.printStackTrace();  
  17.                 }  
  18.             }  
  19.         }  
  20.         //遍历方法 将设置注解的方法绑定到相应的view的点击事件中  
  21.         Method methods[]=activityClass.getDeclaredMethods();  
  22.         for(final Method method:methods){  
  23.             BindClick bindClick=method.getAnnotation(BindClick.class);  
  24.             if(bindClick!=null){  
  25.                 int viewId=bindClick.value();  
  26.                 activity.findViewById(viewId).setOnClickListener(new View.OnClickListener() {  
  27.                     @Override  
  28.                     public void onClick(View view) {  
  29.                         try {  
  30.                             //调用该方法  
  31.                             method.setAccessible(true);  
  32.                             method.invoke(activity);  
  33.                         } catch (IllegalAccessException e) {  
  34.                             e.printStackTrace();  
  35.                         } catch (InvocationTargetException e) {  
  36.                             e.printStackTrace();  
  37.                         }  
  38.                     }  
  39.                 });  
  40.             }  
  41.         }  
  42.     }  
  43. }  

第四步:其实上面已经完成了处理,我们只需要调用一下就可以了,像下面那样:

[java]  view plain  copy
  1. setContentView(R.layout.activity_main);  
  2. //必须放在setContentView后面  
  3. InjectUtils.inject(this); 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值