使用:
ViewUtils.inject(this, rootView); // fragment中
源码分析:
public static void inject(Object handler, View view) {
injectObject(handler, new ViewFinder(view)); //ViewFinder是对Fragment中的rootView或Activity的封装,方便调用findViewByid
}
@SuppressWarnings("ConstantConditions")
private static void injectObject(Object handler, ViewFinder finder) {
Class<?> handlerType = handler.getClass(); // activity/fragment
// inject ContentView 对ContentView的注入,少用
ContentView contentView = handlerType.getAnnotation(ContentView.class);
if (contentView != null) {
try {
Method setContentViewMethod = handlerType.getMethod("setContentView", int.class);
setContentViewMethod.invoke(handler, contentView.value());
} catch (Throwable e) {
LogUtils.e(e.getMessage(), e);
}
}
// inject view 对view的注入,用于设置含有@ViewInject注解的View值
Field[] fields = handlerType.getDeclaredFields();
if (fields != null && fields.length > 0) {
for (Field field : fields) {
ViewInject viewInject = field.getAnnotation(ViewInject.class);// 获取含有ViewInject注解的field
if (viewInject != null) {
try {
// 对于Activity:activity.findViewById(R.id.xxx)
// 对于Fragment: viewRoot.findViewById(R.id.xxx)
View view = finder.findViewById(viewInject.value(), viewInject.parentId());
if (view != null) {
field.setAccessible(true);
field.set(handler, view);
}
} catch (Throwable e) {
LogUtils.e(e.getMessage(), e);
}
}
}
}
// inject event 注入事件
Method[] methods = handlerType.getDeclaredMethods();
if (methods != null && methods.length > 0) {
for (Method method : methods) {
Annotation[] annotations = method.getDeclaredAnnotations();
// 获取所有含有注解的方法(如含有OnClick注解的方法)
if (annotations != null && annotations.length > 0) {// 遍历Activity/Fragment中的所有含有注解的方法
for (Annotation annotation : annotations) { // 遍历所有方法上的注解
// 获取注解的注解。例:OnClick的注解上还有元注解为:EventBase
Class<?> annType = annotation.annotationType(); // 注解类,比如OnClick注解。annType代表OnClick对象
if (annType.getAnnotation(EventBase.class) != null) { // 如果函数的注解的注解上还含有EventBase这种注解
method.setAccessible(true);
// 获取OnClick注解上的value值,一般为R.id.XX(如某个Button的id)
Method valueMethod = annType.getDeclaredMethod("value");
Method parentIdMethod = null;
Object values = valueMethod.invoke(annotation);
Object parentIds = parentIdMethod == null ? null : parentIdMethod.invoke(annotation);
int parentIdsLen = parentIds == null ? 0 : Array.getLength(parentIds); // parentIdsLen为0
int len = Array.getLength(values);
for (int i = 0; i < len; i++) {
// R.id.xxx等数据都封装在ViewInjectInfo类中
ViewInjectInfo info = new ViewInjectInfo();
info.value = Array.get(values, i); // values==R.id.xxx
info.parentId = parentIdsLen > i ? (Integer) Array.get(parentIds, i) : 0;
// info:封装了OnClick注解中的数据信息R.id.xxx
// finder类封装了Activity/Fragment的ViewRoot等信息
// method是Activity/Fragment中带有OnClick注解的方法对象
// annotation注解封装了OnClick注解
// handler:为Activity/Fragment
EventListenerManager.addEventMethod(finder, info, annotation, handler, method);
}
}
}
}
}
}
// TODO 该方法暂未解析,只知道设置监听方法到指定对象中
public static void EventListenerManager.addEventMethod(
ViewFinder finder,
ViewInjectInfo info,
Annotation eventAnnotation,
Object handler,
Method method) {
View view = finder.findViewByInfo(info); // 找到R.id.xxx对应的控件
if (view != null) {
EventBase eventBase = eventAnnotation.annotationType().getAnnotation(EventBase.class);
Class<?> listenerType = eventBase.listenerType(); // View.OnClickListener.class
String listenerSetter = eventBase.listenerSetter(); // "setOnClickListener"
String methodName = eventBase.methodName(); // "onClick"
boolean addNewMethod = false;
Object listener = listenerCache.get(info, listenerType);
DynamicHandler dynamicHandler = null;
if (listener != null) {
dynamicHandler = (DynamicHandler) Proxy.getInvocationHandler(listener);
addNewMethod = handler.equals(dynamicHandler.getHandler());
if (addNewMethod) {
dynamicHandler.addMethod(methodName, method);
}
}
if (!addNewMethod) {
dynamicHandler = new DynamicHandler(handler);
dynamicHandler.addMethod(methodName, method);
listener = Proxy.newProxyInstance(
listenerType.getClassLoader(),
new Class<?>[]{listenerType},
dynamicHandler);
listenerCache.put(info, listenerType, listener);
}
Method setEventListenerMethod = view.getClass().getMethod(listenerSetter, listenerType);
setEventListenerMethod.invoke(view, listener);
}
}
总结:
@ViewInject和@OnClick注解实现:
将Activity或者Fragment的RootView传递给ViewUtils中,ViewUtils对Activity或Fragment的RootView封装成ViewFinder,方便执行
findViewById。当ViewInjdect.inject的时候,反射找到所有含有ViewInject的注解的成员,执行findViewByid来设置View成员的值。
对于含有OnClick的方法,则执行setOnClickListener方法来设置成员函数注解View中
补充:
// EventBase注解
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {
Class<?> listenerType();
String listenerSetter();
String methodName();
}
// OnClick注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventBase(
listenerType = View.OnClickListener.class,
listenerSetter = "setOnClickListener",
methodName = "onClick")
public @interface OnClick {
int[] value();
int[] parentId() default 0;
}
简单的setOnClickListener实现
public class PanViewInjector {
public static void process(final Object o) {
Class c = o.getClass();
Method[] methods = c.getDeclaredMethods();
for (final Method m : methods) {
OnClick click = m.getAnnotation(OnClick.class);//通过反射api获取方法上面的注解
if (click != null) {
if (o instanceof Activity) {
if (click.value() == -1) return;
View view = ((Activity) o).findViewById(click.value());//通过注解的值获取View控件
if (view == null) return;
view.setOnClickListener(new View.OnClickListener() { // 找到方法,重新设置监听,只是调用的方法为之前@OnClick设置的
@Override
public void onClick(View v) {
try {
m.invoke(o);//通过反射来调用被注解修饰的方法
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
}
}
转载请注明原文地址: https://ju.6miu.com/read-1297660.html