美文网首页
浅谈android ioc控制反转一(控件篇)

浅谈android ioc控制反转一(控件篇)

作者: 郭委权 | 来源:发表于2018-05-18 10:57 被阅读0次

    1、ioc介绍

    控制反转(Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。

    到底啥意思呢???

    原本我们在一个类里面用到很多成员变量,都是靠new出来,然后去访问。

    如果咋们运用ioc那就不需要new了,你配置个xml文件,里面写明类名,有哪些成员变量,等加载这个类的时候,ioc帮你new。

     说了这么多好像还没说明白^_^,那就直接上代码~~~~~~

    2、框架

    开发android的小伙伴应该对 butterknife框架应该不陌生吧。笔者对此框架的评价就是:好用,好用,很好用!

    目标:

    @SetContentView(R.layout.activity_main)
    public class MainActivityextends AppCompatActivity {
             @ViewBind(R.id.tv)
             private TextViewtv;  
             @Override
             protected void onCreate(Bundle savedInstanceState) {
                 super.onCreate(savedInstanceState);      
                 ViewInjectUtils.inject(this);     
                 tv.setOnClickListener(new View.OnClickListener()
                {
                     @Override          
                      public void onClick(View v) {  
                           Toast.makeText(MainActivity.this,"我被点击了",Toast.LENGTH_LONG).show();        
                }   
         });
       }
    }

    这里省去了tv控件创建的代码 和 xml文件的加载。其中控件创建时咋们最讨厌的事情,一直重复findViewById。

    SetContentView用于在类上使用,主要标明该Activity需要使用的布局文件。
    ViewBind在字段上使用,主要标明该字段绑定的控件id。

    3.框架实现

    首先先来写SetContentView和ViewBind这两个注解类
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;
    /**
    *描述:
    * * @author guoweiquan * @version 1.0
    * @data 2018/5/14 下午2:15
    */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SetContentView
    {
    int value();
    }
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    /**
    *描述:
    * * @author guoweiquan
    * @version 1.0
    * @data 2018/5/14 下午2:25 */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ViewBind{
           int value();
    }

    解释下注解:@interface代表是注解类 ;
    @Target表示该注解可以用于什么地方(ElementType系统枚举类),
    总共类型如下:
            @Target(ElementType.TYPE)//接口、类、枚举、注解
            @Target(ElementType.FIELD)//字段、枚举的常量
            @Target(ElementType.METHOD)//方法
            @Target(ElementType.PARAMETER)//方法参数
            @Target(ElementType.CONSTRUCTOR)//构造函数
            @Target(ElementType.LOCAL_VARIABLE)//局部变量
            @Target(ElementType.ANNOTATION_TYPE)//注解
             @Target(ElementType.PACKAGE) //包
             @Retention表示:表示需要在什么级别保存该注解信息;我们这里设置为运行时.总共类型如下:
              enumRetentionPolicy {
                   SOURCE,
                   CLASS,
                   RUNTIME
                 }

    下面来看下viewInjectUtils的实现:

    import android.app.Activity;

    import java.lang.reflect.Field;import java.lang.reflect.Method;

    /**
    *描述:
    * * @author guoweiquan
    * @version 1.0
    * @data 2018/5/14 下午2:19
    */

    public class ViewInjectUtils {

    private static final StringSETCONTENTVIEW ="setContentView"; 
    private static final StringFINDVIEWBYID ="findViewById"; 
    public static void inject(Activity activity)  
    {

           bindContentView(activity);   
           bindViews(activity);  
    }

    /**   
      * 绑定主布局文件      
      * @param activity   
      */ 
    private static void bindContentView(Activity activity)
    {     
            Class clazz = activity.getClass();  
            SetContentView contentView = clazz.getAnnotation(SetContentView.class);
           // 查询类上SetContentView注解     
           if (contentView !=null)     
           {
              int contentViewLayoutId = contentView.value();
              try{             
                          Method method = clazz.getMethod(SETCONTENTVIEW, int.class);   

                          method.setAccessible(true);
                         //设置可以访问private域              
                          method.invoke(activity, contentViewLayoutId);
                     }catch (Exception e)         
                 {              
                     e.printStackTrace();         
                  }     
               }  
    }

    /**  
      * 绑定所有的控件     
      * @param activity   
      */ 
    private static void bindViews(Activity activity)  
    {      
            Class clazz = activity.getClass();      
             Field[] fields = clazz.getDeclaredFields();//获取自己声明的各种字段,包public,protected,private           for (Field field : fields)     
             {
                  ViewBind viewInjectAnnotation = field.getAnnotation(ViewBind.class);         
                 if (viewInjectAnnotation !=null)
                 {
                        int viewId = viewInjectAnnotation.value();              
                        if (viewId != -1)             
                        {
                             try{
                                      Method method = clazz.getMethod(FINDVIEWBYID,  int.class);
                                      Object view = method.invoke(activity, viewId);//找到相应控件对象    

                                       field.setAccessible(true);
                                       field.set(activity, view);//给本字段赋值                 
                                    }catch (Exception e)                 
                                    {                      
                                          e.printStackTrace();                
                                       }       
                             }        
                     }     
               }  
            }
     }

    在MainActivity创建时候inject方法被调用,其中bindContentView和bindViews这两个方法 就是帮咋们把加载xml和创建控件的活给干了。

    结果如下:

    项目github地址:https://github.com/seaeel/AndroidIoc.git

    博主技术交流群:239025382

    相关文章

      网友评论

          本文标题:浅谈android ioc控制反转一(控件篇)

          本文链接:https://www.haomeiwen.com/subject/chowdftx.html