android依赖注入注解的实现
2017-04-01 15:06
399 查看
android依赖注入,注解功能,本demo实现view注入,点击事件注入.
首先实现两个注解类:
接下来需要编写注解的解释类:
首先抽象出一个接口类:
功能实现,最后看一下在MainActivity中的使用
首先实现两个注解类:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface InjectView { //只接收一个int类型的值,用于表示view的id public @IdRes int value(); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface OnClick { //接收一个int[],表示可以接收多个view的id,绑定到同一个click执行方法上 public @IdRes int[] value(); }
接下来需要编写注解的解释类:
首先抽象出一个接口类:
//这个泛型接口接收一个AnnotatedElement的子类,它是什么呢? //在Java中,Field,Method,Constructor…一切可注解的对象都实现了AnnotatedElement接口。 public interface ProcessorIntf<T extends AnnotatedElement> { /* * 每个不同的处理器都会通过这个方法来告诉最终的调度者,这个注解是否由我来处理 */ public boolean accept(AnnotatedElement t); /* *第一个object是目标对象, *第二个view是根view *第三个是加上注解的值 */ public void process(Object object, View view, T ao); }具体解释类需实现此接口,InjectViewProcessor类用来解释Field属性,OnClickProcessor类用来解释Method方法
public class InjectViewProcessor implements ProcessorIntf<Field>{ @Override public boolean accept(AnnotatedElement e) { //如果当前这个AnnotatedElement实例加有InjectView注解,则返回true return e.isAnnotationPresent(InjectView.class); } @Override public void process(Object object, View view, Field field) { //如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null InjectView iv = field.getAnnotation(InjectView.class); if(iv != null) { final int viewId = iv.value(); //获取注解值(找到控件的id) final View v = view.findViewById(viewId); //通过根view查找此id对应的view field.setAccessible(true); //设置属性值的访问权限 try { field.set(object, v); //将查找到的view指定给目标对象object } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } }
public class OnClickProcessor implements ProcessorIntf<Method> { @Override public boolean accept(AnnotatedElement e) { //这个很简单,就是告诉管理器我响应OnClick注解 return e.isAnnotationPresent(OnClick.class); } @Override public void process(Object object,View view, Method method) { //先拿到具体的注解对象 ,并拿到里面的值 final OnClick oc = method.getAnnotation(OnClick.class); final int[] value = oc.value(); //遍历id值设置点击事件将方法method与目标对象object传给监听事件 for (int id : value) { view.findViewById(id).setOnClickListener(new InvokeOnClickListener(method,object)); } } //这里面的InvokeOnClickListener是一个中间件,注册给系统,系统在得到点击事件后, //通知给InvokeOnClickListener,在这个里面再调用你所指定的方法。 private static class InvokeOnClickListener implements View.OnClickListener { public Method method; public WeakReference<Object> obj; private boolean hasParam; InvokeOnClickListener(Method m, Object object) { this.method = m; //使用一个WeakReference this.obj = new WeakReference<Object>(object); //先拿到方法的参数,看看有没有参数 , 没有就纪录下hasParam为false final Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes == null || parameterTypes.length == 0) { hasParam = false; //如果有参数的话,判断参数个数,并且判断参数类型是否为view //isAssignableFrom方法用来判断一个类Class1和另一个类Class2是否相同或是另一个类的子类或接口 } else if (parameterTypes.length > 1 || !View.class.isAssignableFrom(parameterTypes[0])) { throw new IllegalArgumentException(String.format("%s方法只能拥有0个或一个参数,且只接收View", m.getName())); } else { //有一个合格参数则返回true hasParam = true; } } @Override public void onClick(View v) { //点击事件触发了 Object o = obj.get(); if (o != null) { try { if (hasParam) { method.invoke(o, v); //有参数,就把view设置过去 } else { method.invoke(o); //没有参数就直接调 } } catch (Exception e) { e.printStackTrace(); } } } } }接下来为了方便使用需要加一个管理类
public class Injector { private static List<? extends ProcessorIntf<? extends AccessibleObject>> chain = Arrays.asList(new InjectViewProcessor(), new OnClickProcessor()); public static void inject(Activity act) { //传入activity实例和rootview inject(act,act.getWindow().getDecorView()); } public static void inject(Object obj, View rootView) { final Class<?> aClass = obj.getClass(); //获取当前活动中所有声明的属性,包括私有属性 final Field[] declaredFields = aClass.getDeclaredFields(); for (Field f : declaredFields) { doChain(obj,f,rootView); } //获取当前活动中所有声明的方法,包括私有方法 final Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method m : declaredMethods) { doChain(obj, m, rootView); } } //把每个遍历到的方法或者属性,甚至是构造方法,类等等通过处理器链来询问这个注解你accept吗?接受则交给它来处理 private static void doChain(Object obj,AccessibleObject ao, View rootView) { for (ProcessorIntf p : chain) { //判断当前AccessibleObject(Field,Method都继承了此类)是否为ProcessorIntf具体子类类型的注解 if(p.accept(ao)) { p.process(obj,rootView,ao); } } } }
功能实现,最后看一下在MainActivity中的使用
public class MainActivity extends Activity { @InjectView(R.id.tv) private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化 Injector.inject(this); } @OnClick({R.id.bt1,R.id.bt2}) public void btnClick(Button view) { final int id = view.getId(); if (id == R.id.bt1) { mTextView.setText("按钮一被点击"); }else if (id == R.id.bt2) { mTextView.setText("按钮二被点击"); } } }
相关文章推荐
- android使用篇(四) 注解依赖注入IOC实现绑定控件
- 2014-05-08android使用篇(四) 注解依赖注入IOC实现绑定控件
- android使用篇(四) 注解依赖注入IOC实现绑定控件
- spring3——注解实现Bean依赖注入
- Spring-Context的注解实现依赖注入功能
- 用Dagger2在Android中实现依赖注入
- [AngularJS面面观] 17. 依赖注入 --- 注解的定义与实现
- 零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3
- 用Dagger2在Android中实现依赖注入
- Android依赖注入之BufferKnife 8.0注解使用
- 跟我学Spring3--注解实现Bean依赖注入
- 注解实现Bean依赖注入
- Spring学习3—控制反转(IOC)基于Annotation(注解)的依赖注入实现
- 开涛spring3(12.2) - 零配置 之 12.2 注解实现Bean依赖注入
- 注解实现Bean依赖注入
- Spring基础 注解实现Bean依赖注入
- 【第十二章】零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3
- Android依赖注入的实现
- SpringMVC实现依赖注入的几个常用注解的用法解释和示例说明
- spring 框架中的依赖注入(IOC--设值注入)--使用注解--的具体实例的简单实现