转载:http://www.apkbus.com/forum.php?mod=viewthread&tid=157641&highlight=xUtils
案例下载:http://download.csdn.net/detail/huningjun/8645595或者https://github.com/wyouflf/xUtils
xUtils可以减少我们很多重复性的工作,加快我们的开发速度。但是我们很有必要去了解一下它到底是怎么实现的。
因为需求总是变化的。可能有一天,我们需要去修改里面的一些东西。所以不但要知其然,还要知其所以然。
在view创建以后,xUtils只调用了以下这个方法,就实现了注入view和事件。
ViewUtils.inject(this,view); //注入view和事件
它到底做了什么事情呢?它的具体代码如下:
- @SuppressWarnings("ConstantConditions")
- private static void injectObject(Object handler, ViewFinder finder) {
- // 注入view
- Field[] fields = handler.getClass().getDeclaredFields();
- if (fields != null && fields.length > 0) {
- for (Field field : fields) {
- //得到注解
- ViewInject viewInject = field.getAnnotation(ViewInject.class);
- if (viewInject != null) {
- try {
- //根据id找到view
- View view = finder.findViewById(viewInject.value(), viewInject.parentId());
- if (view != null) {
- field.setAccessible(true);
- //绑定view
- field.set(handler, view);
- }
- } catch (Throwable e) {
- LogUtils.e(e.getMessage(), e);
- }
- } else {
- //得到注解
- ResInject resInject = field.getAnnotation(ResInject.class);
- if (resInject != null) {
- try {
- //根据id和资源类型load资源
- Object res = ResLoader.loadRes(
- resInject.type(), finder.getContext(), resInject.id());
- if (res != null) {
- field.setAccessible(true);
- field.set(handler, res);
- }
- } catch (Throwable e) {
- LogUtils.e(e.getMessage(), e);
- }
- } else {
- //得到注解
- PreferenceInject preferenceInject = field.getAnnotation(PreferenceInject.class);
- if (preferenceInject != null) {
- try {
- 根据id找到对应的Preference
- Preference preference = finder.findPreference(preferenceInject.value());
- if (preference != null) {
- field.setAccessible(true);
- field.set(handler, preference);
- }
- } catch (Throwable e) {
- LogUtils.e(e.getMessage(), e);
- }
- }
- }
- }
- }
- }
- // 注入事件
- Method[] methods = handler.getClass().getDeclaredMethods();
- if (methods != null && methods.length > 0) {
- String eventName = OnClick.class.getCanonicalName();
- String prefix = eventName.substring(0, eventName.lastIndexOf('.'));
- DoubleKeyValueMap<ViewInjectInfo, Annotation, Method> info_annotation_method_map = new DoubleKeyValueMap<ViewInjectInfo, Annotation, Method>();
- for (Method method : methods) {
- Annotation[] annotations = method.getDeclaredAnnotations();
- if (annotations != null && annotations.length > 0) {
- for (Annotation annotation : annotations) {
- Class<?> annType = annotation.annotationType();
- if (annType.getAnnotation(EventBase.class) != null) {
- if (annType.getCanonicalName().startsWith(prefix)) {
- try {
- // ProGuard:-keep class * extends java.lang.annotation.Annotation { *; }
- Method valueMethod = annType.getDeclaredMethod("value");
- Method parentIdMethod = null;
- try {
- parentIdMethod = annType.getDeclaredMethod("parentId");
- } catch (Throwable e) {
- }
- Object values = valueMethod.invoke(annotation);
- Object parentIds = parentIdMethod == null ? null : parentIdMethod.invoke(annotation);
- 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) : 0;
- info_annotation_method_map.put(info, annotation, method);
- }
- } catch (Throwable e) {
- LogUtils.e(e.getMessage(), e);
- }
- } else {
- ViewCustomEventListener listener = annotationType_viewCustomEventListener_map.get(annType);
- if (listener != null) {
- listener.setEventListener(handler, finder, annotation, method);
- }
- }
- }
- }
- }
- }
- ViewCommonEventListener.setAllEventListeners(handler, finder, info_annotation_method_map);
- }
- }
其实实现非常简单。首先是根据反射获得类的所有字段然后根据注解,得到控件的id,然后在view里找到控件。然后field.setAccessible(true);
field.set(handler,res);让声明的控件,和view里的控件关联起来。
资源类或根据资源id和资源类型加载到对应的资源。方法如下:ResLoader.loadRes(resInject.type(),finder.getContext(), resInject.id());
Preference也会根据id找到对应的值。
绑定事件的方式也是类似。代码如下:
- @SuppressWarnings("ConstantConditions")
- public static void setAllEventListeners(
- Object handler,
- ViewFinder finder,
- DoubleKeyValueMap<ViewInjectInfo, Annotation, Method> info_annotation_method_map) {
-
- for (ViewInjectInfo info : info_annotation_method_map.getFirstKeys()) {
- ConcurrentHashMap<Annotation, Method> annotation_method_map = info_annotation_method_map.get(info);
- for (Annotation annotation : annotation_method_map.keySet()) {
- try {
- Method method = annotation_method_map.get(annotation);
- if (annotation instanceof OnClick) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //view.setOnClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnClickListener", OnClickListener.class, listener);
- } else if (annotation instanceof OnLongClick) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //view.setOnLongClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnLongClickListener", OnLongClickListener.class, listener);
- } else if (annotation instanceof OnFocusChange) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //view.setOnFocusChangeListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnFocusChangeListener", OnFocusChangeListener.class, listener);
- } else if (annotation instanceof OnKey) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //view.setOnKeyListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnKeyListener", OnKeyListener.class, listener);
- } else if (annotation instanceof OnTouch) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //view.setOnTouchListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnTouchListener", OnTouchListener.class, listener);
- } else if (annotation instanceof OnItemClick) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((AdapterView<?>) view).setOnItemClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnItemClickListener", OnItemClickListener.class, listener);
- } else if (annotation instanceof OnItemLongClick) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((AdapterView<?>) view).setOnItemLongClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnItemLongClickListener", OnItemLongClickListener.class, listener);
- } else if (annotation instanceof OnChildClick) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((ExpandableListView) view).setOnChildClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnChildClickListener", ExpandableListView.OnChildClickListener.class, listener);
- } else if (annotation instanceof OnGroupClick) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((ExpandableListView) view).setOnGroupClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnGroupClickListener", ExpandableListView.OnGroupClickListener.class, listener);
- } else if (annotation instanceof OnGroupCollapse) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((ExpandableListView) view).setOnGroupCollapseListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnGroupCollapseListener", ExpandableListView.OnGroupCollapseListener.class, listener);
- } else if (annotation instanceof OnGroupExpand) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((ExpandableListView) view).setOnGroupExpandListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnGroupExpandListener", ExpandableListView.OnGroupExpandListener.class, listener);
- } else if (annotation instanceof OnCheckedChange) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- if (view instanceof RadioGroup) {
- //((RadioGroup) view).setOnCheckedChangeListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnCheckedChangeListener", RadioGroup.OnCheckedChangeListener.class, listener);
- } else if (view instanceof CompoundButton) {
- //((CompoundButton) view).setOnCheckedChangeListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnCheckedChangeListener", CompoundButton.OnCheckedChangeListener.class, listener);
- }
- } else if (annotation instanceof OnPreferenceClick) {
- Preference preference = finder.findPreference(info.value.toString());
- if (preference == null) break;
- //preference.setOnPreferenceClickListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(preference, "setOnPreferenceClickListener", Preference.OnPreferenceClickListener.class, listener);
- } else if (annotation instanceof OnPreferenceChange) {
- Preference preference = finder.findPreference(info.value.toString());
- if (preference == null) break;
- //preference.setOnPreferenceChangeListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(preference, "setOnPreferenceChangeListener", Preference.OnPreferenceChangeListener.class, listener);
- } else if (annotation instanceof OnTabChange) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //((TabHost) view).setOnTabChangedListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "setOnTabChangedListener", TabHost.OnTabChangeListener.class, listener);
- } else if (annotation instanceof OnScrollChanged) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- //view.getViewTreeObserver().addOnScrollChangedListener(new ViewCommonEventListener(handler, method));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method);
- setEventListener(view, "addOnScrollChangedListener", ViewTreeObserver.OnScrollChangedListener.class, listener);
- } else if (annotation instanceof OnScrollStateChanged) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- Method method0 = null, method1 = null;
- ConcurrentHashMap<Annotation, Method> a_m_map = info_annotation_method_map.get(info);
- for (Annotation a : a_m_map.keySet()) {
- if (a instanceof OnScrollStateChanged) {
- method0 = a_m_map.get(a);
- } else if (a instanceof OnScroll) {
- method1 = a_m_map.get(a);
- }
- }
- //((AbsListView) view).setOnScrollListener(new ViewCommonEventListener(handler, method0, method1));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method0, method1);
- setEventListener(view, "setOnScrollListener", AbsListView.OnScrollListener.class, listener);
- } else if (annotation instanceof OnItemSelected) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- Method method0 = null, method1 = null;
- ConcurrentHashMap<Annotation, Method> a_m_map = info_annotation_method_map.get(info);
- for (Annotation a : a_m_map.keySet()) {
- if (a instanceof OnItemSelected) {
- method0 = a_m_map.get(a);
- } else if (a instanceof OnNothingSelected) {
- method1 = a_m_map.get(a);
- }
- }
- //((AdapterView<?>) view).setOnItemSelectedListener(new ViewCommonEventListener(handler, method0, method1));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method0, method1);
- setEventListener(view, "setOnItemSelectedListener", AbsListView.OnItemSelectedListener.class, listener);
- } else if (annotation instanceof OnProgressChanged) {
- View view = finder.findViewByInfo(info);
- if (view == null) break;
- Method method0 = null, method1 = null, method2 = null;
- ConcurrentHashMap<Annotation, Method> a_m_map = info_annotation_method_map.get(info);
- for (Annotation a : a_m_map.keySet()) {
- if (a instanceof OnProgressChanged) {
- method0 = a_m_map.get(a);
- } else if (a instanceof OnStartTrackingTouch) {
- method1 = a_m_map.get(a);
- } else if (a instanceof OnStopTrackingTouch) {
- method2 = a_m_map.get(a);
- }
- }
- //((SeekBar) view).setOnSeekBarChangeListener(new ViewCommonEventListener(handler, method0, method1, method2));
- ViewCommonEventListener listener = new ViewCommonEventListener(handler, method0, method1, method2);
- setEventListener(view, "setOnSeekBarChangeListener", SeekBar.OnSeekBarChangeListener.class, listener);
- }
- } catch (Throwable e) {
- LogUtils.e(e.getMessage(), e);
- }
- }
- }
- }
-
- private static void setEventListener(Object view,
- String setEventListenerMethod,
- Class<?> eventListenerType,
- ViewCommonEventListener listener) {
- try {
- Method setMethod = view.getClass().getMethod(setEventListenerMethod, eventListenerType);
- if (setMethod != null) {
- setMethod.invoke(view, listener);
- }
- } catch (Throwable e) {
- LogUtils.e(e.getMessage(), e);
- }
- }