@yudesong
2018-02-12T03:13:14.000000Z
字数 6894
阅读 703
xUtils
本文使是以xUtils 2.6的版本来解析源码,可分为以下几个部分:

首先来看看FileNameGenerator这个接口,其中有一个方法generate方法,生成文件名称,MD5FileNameGenerator实现了该方法,并且采用MD5算法。
public String generate(String key) {String cacheKey;try {final MessageDigest mDigest = MessageDigest.getInstance("MD5");mDigest.update(key.getBytes());cacheKey = bytesToHexString(mDigest.digest());} catch (NoSuchAlgorithmException e) {cacheKey = String.valueOf(key.hashCode());}return cacheKey;}private String bytesToHexString(byte[] bytes) {StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(0xFF & bytes[i]);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString();}
KeyExpiryMap继承自ConcurrentHashMap,存储类型为范型其中Long保存了该key的保存的时间戳。
@Overridepublic synchronized Long put(K key, Long expiryTimestamp) {if (this.containsKey(key)) {this.remove(key);}return super.put(key, expiryTimestamp);}@Overridepublic synchronized boolean containsKey(Object key) {boolean result = false;Long expiryTimestamp = super.get(key);if (expiryTimestamp != null && System.currentTimeMillis() < expiryTimestamp) {result = true;} else {this.remove(key);}return result;}
LruMemoryCache 为实现了最近最少使用算法,可参考这边博客Java 最近最少使用算法(LRU)。其内部保存了一个LinkedHashMap、KeyExpiryMap对象的应用。
public final V get(K key) {if (key == null) {throw new NullPointerException("key == null");}V mapValue;synchronized (this) {// If expired, remove the entry.if (!keyExpiryMap.containsKey(key)) {this.remove(key);return null;}mapValue = map.get(key);if (mapValue != null) {hitCount++;return mapValue;}missCount++;}/** Attempt to create a value. This may take a long time, and the map* may be different when create() returns. If a conflicting value was* added to the map while create() was working, we leave that value in* the map and release the created value.*/V createdValue = create(key);if (createdValue == null) {return null;}synchronized (this) {createCount++;mapValue = map.put(key, createdValue);if (mapValue != null) {// There was a conflict so undo that last putmap.put(key, mapValue);} else {size += safeSizeOf(key, createdValue);}}if (mapValue != null) {entryRemoved(false, key, createdValue, mapValue);return mapValue;} else {trimToSize(maxSize);return createdValue;}}public final V put(K key, V value) {return put(key, value, Long.MAX_VALUE);}public final V put(K key, V value, long expiryTimestamp) {if (key == null || value == null) {throw new NullPointerException("key == null || value == null");}V previous;synchronized (this) {putCount++;size += safeSizeOf(key, value);previous = map.put(key, value);keyExpiryMap.put(key, expiryTimestamp);if (previous != null) {size -= safeSizeOf(key, previous);}}if (previous != null) {entryRemoved(false, key, previous, value);}trimToSize(maxSize);return previous;}private void trimToSize(int maxSize) {while (true) {K key;V value;synchronized (this) {if (size <= maxSize || map.isEmpty()) {break;}Map.Entry<K, V> toEvict = map.entrySet().iterator().next();key = toEvict.getKey();value = toEvict.getValue();map.remove(key);keyExpiryMap.remove(key);size -= safeSizeOf(key, value);evictionCount++;}entryRemoved(true, key, value, null);}}public final V remove(K key) {if (key == null) {throw new NullPointerException("key == null");}V previous;synchronized (this) {previous = map.remove(key);keyExpiryMap.remove(key);if (previous != null) {size -= safeSizeOf(key, previous);}}if (previous != null) {entryRemoved(false, key, previous, null);}return previous;}
ContentView 、ViewInject、OnClick注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ContentView {int value();}@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface ViewInject {int value();/* parent view id */int parentId() default 0;}@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@EventBase(listenerType = View.OnClickListener.class,listenerSetter = "setOnClickListener",methodName = "onClick")public @interface OnClick {int[] value();int[] parentId() default 0;}
最主要的类就是ViewUtils。
public static void inject(Activity activity) {injectObject(activity, new ViewFinder(activity));}@SuppressWarnings("ConstantConditions")private static void injectObject(Object handler, ViewFinder finder) {Class<?> handlerType = handler.getClass();// inject ContentViewContentView 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 viewField[] fields = handlerType.getDeclaredFields();if (fields != null && fields.length > 0) {for (Field field : fields) {ViewInject viewInject = field.getAnnotation(ViewInject.class);if (viewInject != null) {try {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);}} else {ResInject resInject = field.getAnnotation(ResInject.class);if (resInject != null) {try {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 {Preference preference = finder.findPreference(preferenceInject.value());if (preference != null) {field.setAccessible(true);field.set(handler, preference);}} catch (Throwable e) {LogUtils.e(e.getMessage(), e);}}}}}}// inject eventMethod[] methods = handlerType.getDeclaredMethods();if (methods != null && methods.length > 0) {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) {method.setAccessible(true);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;EventListenerManager.addEventMethod(finder, info, annotation, handler, method);}} catch (Throwable e) {LogUtils.e(e.getMessage(), e);}}}}}}}
其中ViewFinder类如下:
```
public class ViewFinder {
private View view;
private Activity activity;
public ViewFinder(View view) {
this.view = view;
}
public ViewFinder(Activity activity) {
this.activity = activity;
}
......
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;
}
@SuppressWarnings("deprecation")
public Preference findPreference(CharSequence key) {
return preferenceGroup == null ? preferenceActivity.findPreference(key) : preferenceGroup.findPreference(key);
}
}
```
参考文章
1.trimToSize 用法