注解初始化控件(XUtils方式)
2016-03-29 11:37
441 查看
新博客地址
注解初始化控件(XUtils方式)
DEMO链接地址
在第一次潭州教育的公开课上接触了这个框架的讲解,我动手研究了一下,结果一出手就停不下来,先后被我碰上了(Glow公司的技术博客——动态Android编程 )、从几个大牛的博客(学到了github pages + Jekyll 免费制作博客网站)我发现不写博客,很多东西就会忘记(代码如何上传到jcenter我已经忘记了)
Just Do it!真的会有意想不到的收获!
1. IOC概念介绍
http://www.cnblogs.com/qqlin/archive/2012/10/09/2707075.html我是从这边文章学习的IOC概念的,写的浅显易懂
控件反转(IOC):创建何种对象的控制权,转移到第三方
依赖注入(DI):是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。
IOC与DI之间的关系:DI是一种IOC的具体思想,(编译运行期,动态注入依赖关系);使用配置文件实现依赖关系的配置也是一种IOC思想(依赖拖拽)。
约定优于配置 这个是什么鬼??
依赖注入/依赖查找/依赖拖拽
依赖拖拽是通过对注入对象的集中配置实现的
依赖查找是在业务组件代码中进行的(EJB和Apache Avalon )
XUtils的实现方式XUtils实际上是通过 注解 + 反射 + 动态代理实现的。
layout文件注入:
使用:@ContentViewInject(R.layout.activity_main) public class MainActivity extends AppCompatActivity
注解:
@Target(ElementType.TYPE)// 使用对象:类 @Retention(RetentionPolicy.RUNTIME)// 生命范围:运行期 public @interface ContentViewInject { int value();// 存放布局id }
注入代码:
private static void injectLayout(Activity context) { try { // UIClz Class<? extends Context> uiClass = context.getClass(); // 类上的注解 ContentViewInject annotation = uiClass.getAnnotation(ContentViewInject.class); if (annotation != null) { // 注解中的layout id值 int value = annotation.value(); // 通过反射使用activity中的setContentView方法进行 布局设置 // 局限性:这个方法仅仅适用于activity Method setContentView = uiClass.getMethod("setContentView", int.class); setContentView.invoke(context, value); } } catch (Exception e) { e.printStackTrace(); } }
控件注入:
使用:@ViewInject(R.id.textView) TextView textView; ...... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TurInject.bind(this); textView.setText("徕帝嘎嘎"); }
注解:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ViewInject { int value(); }
注入:
private static void injectViews(Context context) { try { Class<? extends Context> uiClass = context.getClass(); // 获取成员变量 Field[] fields = uiClass.getDeclaredFields(); for (Field field : fields) { ViewInject annotation = field.getAnnotation(ViewInject.class); if (annotation != null) { int value = annotation.value(); Method findViewById = uiClass.getMethod("findViewById", int.class); Object invoke = findViewById.invoke(context, value); // 设置允许访问 field.setAccessible(true); field.set(context, invoke); } } } catch (Exception e) { e.printStackTrace(); } }
事件注入
使用代码:@ClickEvent(value = {R.id.textView}, type = View.OnClickListener.class) public void ccClick(View view) { Toast.makeText(getBaseContext(), "ccClick", Toast.LENGTH_LONG).show(); } @ClickEvent(value = {R.id.textView}, type = View.OnLongClickListener.class) public void longClick(View view) { Toast.makeText(getBaseContext(), "longClick", Toast.LENGTH_LONG).show(); }
注解
public static void injectMethod(final Context context) { try { Class<? extends Context> uiClass = context.getClass(); // 获取所有的方法 Method[] methods = uiClass.getMethods(); for (final Method method : methods) { ClickEvent annotation = method.getAnnotation(ClickEvent.class); // 塞选含有ClickEvent注解的方法 if (annotation != null) { int[] values = annotation.value(); Class type = annotation.type(); // 拿到控件 for (int viewId : values) { // 初始化控件 Method findViewById = uiClass.getMethod("findViewById", int.class); // view final Object viewObj = findViewById.invoke(context, viewId); Class<?> viewClass = viewObj.getClass(); // setOnClickListener/setOnLongClickListener等等 String viewSetMethodName = "set" + type.getSimpleName(); Method viewMethod = viewClass.getMethod(viewSetMethodName, type); // 动态代理就是针对 任意 一个对象的接口方法的 管理/拦截/AOP ViewEventInvocationHandler viewEventInvocationHandler = new ViewEventInvocationHandler(context, method); // type.getClassLoader : 类加载器 new Class[]{type} : type为接口类 Object eventInterfaceInstance = Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, viewEventInvocationHandler); // 动态代理 OnClickListener 中的 // 执行了setOnClickListener这个方法,那么在响应这个参数OnClickListener接口中的,onclick方法的时候会响应InvocationHandler中的invoke方法 viewMethod.invoke(viewObj, eventInterfaceInstance); } } } } catch (Exception e) { e.printStackTrace(); } } public static class ViewEventInvocationHandler implements InvocationHandler { private Context context; private Method contentMethod; public ViewEventInvocationHandler(Context context, Method contentMethod) { this.context = context; this.contentMethod = contentMethod; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // method 为OnClickListener 中的 onClick // 系统调用参数接口中的 onClick方法的时候,会响应这个方法 // 响应这个方法的时候我们需要响应(activity中被ClickEvent标记过的方法) // contentMethod 为activity中被 ClickEvent标记过的方法 contentMethod.invoke(context, args); return true; } }
知乎——代理、动态代理
主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。
还有一个有趣的作用是可以用作远程调用
在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
为其他对象提供一种代理以控制对这个对象的访问
动态代理的缺憾:Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏
到这里呢,XUtils的布局注入、控件注入、事件注入就全部介绍完了!
相关文章推荐
- 面试算法——排序
- mysql 利用自增数据项的方法,对同一个表有某种关联的数据进行处理。(利用增加一项的方法)
- eclipse从数据库逆向生成Hibernate实体类
- [查异常网]-20160329-Java ConcurrentModificationException异常原因和解决方法
- jQuery实现图片加载完成后改变图片大小的方法
- Cannot add header view to list -- setAdapter has already been called.
- 五.管理使用者和设立权限的命令
- 四.有关关机和查看系统信息的命令
- Activity的四种启动模式和onNewIntent()
- Swift--map函数浅析
- 机器视觉开源代码集合
- db2 存储过程迁移方法
- javascript实现深克隆的几种方法
- [转载]ORA-00313:无法打开日志组1(线程 1)的成员_ORA-00312:
- oc类的创建与使用与数组的四种遍历示例
- 常用的正则表达式规则和基本规范
- Back键和Home键的屏蔽
- 如何从layout文件添加 fragment
- 2016329
- C#.NET编码规范