转载:http://www.apkbus.com/forum.php?mod=viewthread&tid=157641&highlight=xUtils
案例下载:http://download.youkuaiyun.com/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);
-
}
-
}