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