xUtils2.x(ViewUtils)
来源:互联网 发布:返利软件是什么 编辑:程序博客网 时间:2024/06/05 07:47
虽然现在都以3.x为主,但是我还是希望能够从源码上学习xUtils的技术,可以从中学到更多的东西,所以先从2.x版本的xUtils入手,深度学习这款综合性框架。
GitHub地址:https://github.com/wyouflf/xUtils ----- 这是xUtils2.x版本
GitHub地址:https://github.com/wyouflf/xUtils3 ----- 这是xUtils3.x版本
xUtils3.x版本依赖:
compile 'org.xutils:xutils:3.3.44'
官方文档已经详细的介绍了其所有功能包括:ViewUtils,DbUtils,HttpUtils,BitmapUtils四大模块。这里首先学习ViewUtils:
ViewUtils是以注解和反射的方式来完成Android界面的UI绑定和事件绑定。首先我们要大概了解注解和反射的概念和大概原理。
@ContentView(R.layout.activity_main)public class MainActivity extends Activity { @ViewInject(R.id.t) private TextView t; @ViewInject(R.id.t1) private TextView t1; @ViewInject(R.id.t2) private TextView t2; private FragmentTransaction fragmentTransaction; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewUtils.inject(this); fragmentTransaction = getFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fl, new TestFragment()); fragmentTransaction.commit(); } @OnClick({R.id.t, R.id.t1, R.id.t2}) public void onClick(View view) { Toast.makeText(this, "111111111", Toast.LENGTH_SHORT).show(); }}
这是activity中的绑定,当然还有fragment的。因为两者调用的方法不同,所以注意两者之间的区别:
public class TestFragment extends Fragment { @ViewInject(R.id.ttt) private TextView textView; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_test, container, false); ViewGroup viewGroup = (ViewGroup) view.getParent(); if (viewGroup != null) viewGroup.removeView(view); ViewUtils.inject(this, view); return view; } @OnClick(R.id.ttt) public void onclick(View view) { Toast.makeText(getActivity(), "1qqqqqqqqq", Toast.LENGTH_SHORT).show(); }
在代码中可以看到三个文本控件和一个fragment的布局,大概知道了整个activity的整个界面,这里就不铺xml了。这里首先可以看到有许多的注解,稍后我们可以在源码中看到这个的实现原理。还有一个主要的方法 ViewUtils.inject(this); 在此一定要在使用ViewUtils的界面中调用这个方法,因为所有对注解的解释都在这里面执行。我们可以进去看一下源码:
public class ViewUtils { ........ public static void inject(Activity activity) { injectObject(activity, new ViewFinder(activity)); } public static void inject(PreferenceActivity preferenceActivity) { injectObject(preferenceActivity, new ViewFinder(preferenceActivity)); } public static void inject(Object handler, View view) { injectObject(handler, new ViewFinder(view)); } public static void inject(Object handler, Activity activity) { injectObject(handler, new ViewFinder(activity)); }....... private static void injectObject(Object handler, ViewFinder finder) { Class handlerType = handler.getClass(); ContentView contentView = (ContentView)handlerType.getAnnotation(ContentView.class); if(contentView != null) { try { Method fields = handlerType.getMethod("setContentView", new Class[]{Integer.TYPE}); fields.invoke(handler, new Object[]{Integer.valueOf(contentView.value())}); } catch (Throwable var28) { LogUtils.e(var28.getMessage(), var28); } } Field[] var30 = handlerType.getDeclaredFields(); int var7; if(var30 != null && var30.length > 0) { Field[] var8 = var30; var7 = var30.length; for(int method = 0; method < var7; ++method) { Field methods = var8[method]; ViewInject viewInject = (ViewInject)methods.getAnnotation(ViewInject.class); if(viewInject != null) { try { View annotations = finder.findViewById(viewInject.value(), viewInject.parentId()); if(annotations != null) { methods.setAccessible(true); methods.set(handler, annotations); } } catch (Throwable var27) { LogUtils.e(var27.getMessage(), var27); } } else { ResInject var35 = (ResInject)methods.getAnnotation(ResInject.class); if(var35 != null) { try { Object annotation = ResLoader.loadRes(var35.type(), finder.getContext(), var35.id()); if(annotation != null) { methods.setAccessible(true); methods.set(handler, annotation); } } catch (Throwable var26) { LogUtils.e(var26.getMessage(), var26); } } else { PreferenceInject var37 = (PreferenceInject)methods.getAnnotation(PreferenceInject.class); if(var37 != null) { try { Preference e = finder.findPreference(var37.value()); if(e != null) { methods.setAccessible(true); methods.set(handler, e); } } catch (Throwable var25) { LogUtils.e(var25.getMessage(), var25); } } } } } } Method[] var31 = handlerType.getDeclaredMethods(); if(var31 != null && var31.length > 0) { Method[] var34 = var31; int var33 = var31.length; for(var7 = 0; var7 < var33; ++var7) { Method var32 = var34[var7]; Annotation[] var36 = var32.getDeclaredAnnotations(); if(var36 != null && var36.length > 0) { Annotation[] var14 = var36; int var13 = var36.length; for(int var39 = 0; var39 < var13; ++var39) { Annotation var38 = var14[var39]; Class annType = var38.annotationType(); if(annType.getAnnotation(EventBase.class) != null) { var32.setAccessible(true); try { Method e1 = annType.getDeclaredMethod("value", new Class[0]); Method parentIdMethod = null; try { parentIdMethod = annType.getDeclaredMethod("parentId", new Class[0]); } catch (Throwable var24) { ; } Object values = e1.invoke(var38, new Object[0]); Object parentIds = parentIdMethod == null?null:parentIdMethod.invoke(var38, new Object[0]); int parentIdsLen = parentIds == null?0:Array.getLength(parentIds); int len = Array.getLength(values); for(int i = 0; i < len; ++i) { ViewInjectInfo info = new ViewInjectInfo(); info.value = Array.get(values, i); info.parentId = parentIdsLen > i?((Integer)Array.get(parentIds, i)).intValue():0; EventListenerManager.addEventMethod(finder, info, var38, handler, var32); } } catch (Throwable var29) { LogUtils.e(var29.getMessage(), var29); } } } } } } }}
在这里源码过长,我们可以看看主要的几个过程:
1.调用 ViewUtils 的 inject 方法,顺便也创建了一个 ViewFinder。
2.通过反射找到所在此上下文中的 ContentView 注解,并找到该上下文的布局,可以看到所有的解释都在 injectObject方法中。
3.同上,通过反射找到此上下文中的 ViewInject 注解,并绑定其注解的控件上、包括资源id和监听事件绑定。
在做一切事情之前就是找到主界面:
Class handlerType = handler.getClass(); ContentView contentView = (ContentView)handlerType.getAnnotation(ContentView.class); if(contentView != null) { try { Method fields = handlerType.getMethod("setContentView", new Class[]{Integer.TYPE}); fields.invoke(handler, new Object[]{Integer.valueOf(contentView.value())}); } catch (Throwable var28) { LogUtils.e(var28.getMessage(), var28); } }在一开始就通过getAnnotation的方法寻找该上下文中指定类型的注解,也就是ContentView类型。这是什么类型呢?就是我们在Activity中最顶层的第一行注解:
@ContentView(R.layout.activity_main)
在没有找到该注解执行接下来的代码,否则会通过反射机制来完成setContentView的界面绑定过程。
接下来就是要绑定控件和资源,因为这里需要使用ViewFinder类,所以我们先看看这个类中提供了什么功能:
public class ViewFinder { private View view; private Activity activity; private PreferenceGroup preferenceGroup; private PreferenceActivity preferenceActivity; public ViewFinder(View view) { this.view = view; } public ViewFinder(Activity activity) { this.activity = activity; } public ViewFinder(PreferenceGroup preferenceGroup) { this.preferenceGroup = preferenceGroup; } public ViewFinder(PreferenceActivity preferenceActivity) { this.preferenceActivity = preferenceActivity; this.activity = preferenceActivity; } public View findViewById(int id) { return this.activity == null?this.view.findViewById(id):this.activity.findViewById(id); } public View findViewByInfo(ViewInjectInfo info) { return this.findViewById(((Integer)info.value).intValue(), info.parentId); } public View findViewById(int id, int pid) { View pView = null; if(pid > 0) { pView = this.findViewById(pid); } View view = null; if(pView != null) { view = pView.findViewById(id); } else { view = this.findViewById(id); } return view; } public Preference findPreference(CharSequence key) { return this.preferenceGroup == null?this.preferenceActivity.findPreference(key):this.preferenceGroup.findPreference(key); } public Context getContext() { return (Context)(this.view != null?this.view.getContext():(this.activity != null?this.activity:(this.preferenceActivity ! = null?this.preferenceActivity:null)));}}
其中可以看到熟悉的findViewById等方法,没错,这里就给ViewUtils提供查找控件的功能。
之后也可以看出在ViewUtils中查找ViewInject的解释对象并使用viewFinder.findViewById来完成控件绑定,所以在控件上看到@ViewInject(R.id.t1)
的控件绑定注解,所有的解释工作都是在这里完成的。在这里也可以看出可以给出父控件的重载方法。
最后就要寻找被注解的监听事件,面对源码需要了解动态代理机制,这里可以看到所使用的是var32.getDeclaredAnnotations();的方法,之前见过和这个类似的方法是以需要寻找的注解class作为参数传递,就会找到该上下文所有对应的变量等,而这里是查找到所有的被标记注解的所有方法。
Method[] var31 = handlerType.getDeclaredMethods(); if(var31 != null && var31.length > 0) { Method[] var34 = var31; int var33 = var31.length; for(var7 = 0; var7 < var33; ++var7) { Method var32 = var34[var7]; Annotation[] var36 = var32.getDeclaredAnnotations(); if(var36 != null && var36.length > 0) { Annotation[] var14 = var36; int var13 = var36.length; for(int var39 = 0; var39 < var13; ++var39) { Annotation var38 = var14[var39]; Class annType = var38.annotationType(); if(annType.getAnnotation(EventBase.class) != null) { var32.setAccessible(true); try { Method e1 = annType.getDeclaredMethod("value", new Class[0]); Method parentIdMethod = null; try { parentIdMethod = annType.getDeclaredMethod("parentId", new Class[0]); } catch (Throwable var24) { ; } Object values = e1.invoke(var38, new Object[0]); Object parentIds = parentIdMethod == null?null:parentIdMethod.invoke(var38, new Object[0]); int parentIdsLen = parentIds == null?0:Array.getLength(parentIds); int len = Array.getLength(values); for(int i = 0; i < len; ++i) { ViewInjectInfo info = new ViewInjectInfo(); info.value = Array.get(values, i); info.parentId = parentIdsLen > i?((Integer)Array.get(parentIds, i)).intValue():0; EventListenerManager.addEventMethod(finder, info, var38, handler, var32); } } catch (Throwable var29) { LogUtils.e(var29.getMessage(), var29); } } } } } }
还有就是在16行可以看到一个EventBase的接口,点进去可以看到他是一个接口注解,所有的监听事件注解也都被该注解注释并向其中添加属性:listenerType(监听器.class),listenerSetter(调用监听器的方法名),mehodName(监听器中方法的名字)。进入for循环后在 20行 和 24行 会去寻找注解中的参数,也就是我们在监听控件上添加参数的资源ID,之后就根据Id数组循环绑定监听器,这里运用到EventListenerManager类。
public class EventListenerManager { private static final DoubleKeyValueMap<ViewInjectInfo, Class<?>, Object> listenerCache = new DoubleKeyValueMap(); private EventListenerManager() { } public static void addEventMethod(ViewFinder finder, ViewInjectInfo info, Annotation eventAnnotation, Object handler, Method method) { try { View e = finder.findViewByInfo(info); if(e != null) { EventBase eventBase = (EventBase)eventAnnotation.annotationType().getAnnotation(EventBase.class); Class listenerType = eventBase.listenerType(); String listenerSetter = eventBase.listenerSetter(); String methodName = eventBase.methodName(); boolean addNewMethod = false; Object listener = listenerCache.get(info, listenerType); EventListenerManager.DynamicHandler dynamicHandler = null; if(listener != null) { dynamicHandler = (EventListenerManager.DynamicHandler)Proxy.getInvocationHandler(listener); addNewMethod = handler.equals(dynamicHandler.getHandler()); if(addNewMethod) { dynamicHandler.addMethod(methodName, method); } } if(!addNewMethod) { dynamicHandler = new EventListenerManager.DynamicHandler(handler); dynamicHandler.addMethod(methodName, method); listener = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, dynamicHandler); listenerCache.put(info, listenerType, listener); } Method setEventListenerMethod = e.getClass().getMethod(listenerSetter, new Class[]{listenerType}); setEventListenerMethod.invoke(e, new Object[]{listener}); } } catch (Throwable var14) { LogUtils.e(var14.getMessage(), var14); } } public static class DynamicHandler implements InvocationHandler { private WeakReference<Object> handlerRef; private final HashMap<String, Method> methodMap = new HashMap(1); public DynamicHandler(Object handler) { this.handlerRef = new WeakReference(handler); } public void addMethod(String name, Method method) { this.methodMap.put(name, method); } public Object getHandler() { return this.handlerRef.get(); } public void setHandler(Object handler) { this.handlerRef = new WeakReference(handler); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object handler = this.handlerRef.get(); if(handler != null) { String methodName = method.getName(); method = (Method)this.methodMap.get(methodName); if(method != null) { return method.invoke(handler, args); } } return null; } }}
- xUtils2.x(ViewUtils)
- ViewUtils
- XUtil学习笔记之ViewUtils(二)
- xUtils(一)-ViewUtils基础用法
- Android高级之xUtils框架(一):ViewUtils的用法
- xUtils类库(BitmapUtils、ViewUtils、DbUtils、HttpUtils)使用介绍
- Xutils完全解析(二):ViewUtils和BitmapUtils
- Android开发之最火的开源框架之一Xutils2详解(摘自开源作者官方介绍详解)
- Android:开源框架xutils介绍之 ViewUtils(注解实现UI绑定和事件绑定)
- xUtils ViewUtils 用法
- ViewUtils模块的使用
- 注解:xUtils之----ViewUtils
- Xutils之ViewUtils解析
- ViewUtils 扩展类问题
- xUtils2和xUtils3的使用及区别
- Xutils2.6不能在Studio里使用
- xutils2.0网络请求的关键代码
- xutils3:ViewUtils.inject,没有inject方法或者没有ViewUtils类
- Linux下两种增加/tmp文件的方法
- 9-2为被装饰的函数保存元数据
- 0002-超声学习笔记-20170324
- 我的WCF之旅(5):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的重载(Overloading)
- 构造方法、package、静态属性、访问控制修饰符知识点
- xUtils2.x(ViewUtils)
- http中post 和 get 请求方法区别大全
- 9-3定义带参数的装饰器
- 加速器陀螺仪基本原理
- 用MFC编程编译时出现LNK2019的错误,解决办法
- 《hive编程指南》阅读笔记摘要(五)
- 中美人才战不可避免,中国能赢吗?
- bitbucket入门手册,手把手操作指南
- 抒发一下这些天用django做web项目的一些体会