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 MainActivity extends AppCompatActivity { @ViewBind(R.id.tv) private TextView tv; @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; /** * <p>描述:<p> * * @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; /** * <p>描述:<p> * * @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) //接口、类、枚举、注解
enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
下面来看下viewInjectUtils的实现:
import android.app.Activity; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * <p>描述:<p> * * @author guoweiquan * @version 1.0 * @data 2018/5/14 下午2:19 */ public class ViewInjectUtils { private static final String SETCONTENTVIEW = "setContentView"; private static final String FINDVIEWBYID = "findViewById"; public static void inject(Activity activity) { bindContentView(activity); bindViews(activity); } /** * 绑定主布局文件 * * @param activity */ private static void bindContentView(Activity activity) { Class<? extends Activity> 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<? extends Activity> 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