一.LayoutInflater类的inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)方法
1.inflate(resource, root)与inflate(resource, root, false)的区别
root非空时,前者会将inflate的View添加到root中,且返回值为root;后者反之,不会将inflate的View添加到root中,且返回值为View。
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
// ... 省略中间代码
View result = root;
//... 省略中间代码
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
//... 省略中间代码
}
root为空时,无区别。
2.inflate(resource)与inflate(resource, root, false), inflate(resource, root)的区别
root不为空时,inflate的View会参考root的宽高,无论attachToRoot是否为true。
二、TextView使用SpannableStringBuilder与ClickableSpan时
1.在使用LinkMovementMethod时,如果同时设置TextView的maxLines,maxLines并不起作用,且点击ClickableSpan时,会导致文字滚动。原因是LinkMovementMethod继承于ScrollingMovementMethod。
解决这个问题:
Can I disable the scrolling in TextView when using LinkMovementMethod?
2.按照1的方式,如果文字最后是ClickableSpan时,最后一行有空白,点击空白处响应的仍然是ClickableSpan,此时需要判断点击处是否是空白,具体修改如下:
public class LinkMovementMethodOverride implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
TextView widget = (TextView) v;
Object text = widget.getText();
if (text instanceof Spanned) {
Spanned buffer = (Spanned) text;
int action = event.getAction();
if (action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off,
ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
int textStart = layout.getLineStart(line);
float lineEnd = 0f;
try {
lineEnd = widget.getPaint().measureText(buffer.toString(), textStart, buffer.length());
} catch (Throwable t) {
LogcatUtils.logException(t);
}
if (x <= lineEnd) {
link[0].onClick(widget);
} else {
widget.performClick();
}
} else if (action == MotionEvent.ACTION_DOWN) {
// Selection only works on Spannable text. In our case setSelection doesn't work on spanned text
//Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
}
return true;
}
}
}
return false;
}
private static LinkMovementMethodOverride instance = new LinkMovementMethodOverride();
public static LinkMovementMethodOverride getInstance() {
return instance;
}
}
3.在使用LinkMovementMethod时如果同时设置ClickableSpan,长按时会导致崩溃
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.widget.Editor$SelectionModifierCursorController.getMinTouchOffset()' on a null object reference
at android.widget.Editor.touchPositionIsInSelection(Editor.java:1114)
at android.widget.Editor.performLongClick(Editor.java:1235)
at android.widget.TextView.performLongClick(TextView.java:11352)
at android.view.View.performLongClick(View.java:6664)
at android.view.View$CheckForLongPress.run(View.java:25886)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:6867)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
之所以出现此崩溃, 是由于调用了
content.setMovementMethod(LinkMovementMethod.getInstance());
此方法内部实现如下:
public final void setMovementMethod(MovementMethod movement) {
if (mMovement != movement) {
mMovement = movement;
if (movement != null && !(mText instanceof Spannable)) {
setText(mText);
}
fixFocusableAndClickableSettings();
// SelectionModifierCursorController depends on textCanBeSelected, which depends on
// mMovement
if (mEditor != null) mEditor.prepareCursorControllers();
}
}
private void fixFocusableAndClickableSettings() {
if (mMovement != null || (mEditor != null && mEditor.mKeyListener != null)) {
setFocusable(true);
setClickable(true);
setLongClickable(true);
} else {
setFocusable(false);
setClickable(false);
setLongClickable(false);
}
}
会导致TextView的longClickable为true。
三、EventBus 2中register()方法
public void register(Object subscriber) {
register(subscriber, false, 0);
}
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
会扫描当前class及其父类的所有onEvent***()系列方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
String key = subscriberClass.getName();
List<SubscriberMethod> subscriberMethods;
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
if (subscriberMethods != null) {
return subscriberMethods;
}
subscriberMethods = new ArrayList<SubscriberMethod>();
Class<?> clazz = subscriberClass;
HashSet<String> eventTypesFound = new HashSet<String>();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
Method[] methods = clazz.getDeclaredMethods();
... // 省略具体分析method代码
clazz = clazz.getSuperclass();
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME);
} else {
synchronized (methodCache) {
methodCache.put(key, subscriberMethods);
}
return subscriberMethods;
}
}
这种可以用在基类中实现EventBus.regsiter()和EventBus.unregister()方法,基类中有一些共有的onEvent***()系列方法,子类中有自己独特的onEvent**()方法的情况。
四、
未完,
持续更新