Android面试的几个问题
1 TextView如何优化?
2 给TextView设置新的字符串,整个布局会重新绘制吗?
3 requestLayout和invalidate方法有什么区别?
TextView如何优化
联想到View的性能优化,一般都是想办法减少measure,layout,draw方法的时间,但是对TextView的优化一般都是给TextView设置固定的宽高,这样在TextView文本发生变化的时候就只会重新走TextView的draw方法,没有重新measure和layout,达到了性能优化的目的。
下面我们直接从源码分析:
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
//...前面省略
if (mLayout != null) {
checkForRelayout();
}
sendOnTextChanged(text, 0, oldlen, textLength);
onTextChanged(text, 0, oldlen, textLength);
if (a11yTextChangeType == AccessibilityUtils.TEXT) {
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
} else if (a11yTextChangeType == AccessibilityUtils.PARCELABLE_SPAN) {
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
} else {
notifyListeningManagersAfterTextChanged();
}
if (mEditor != null) {
// SelectionModifierCursorController depends on textCanBeSelected, which depends on text
mEditor.prepareCursorControllers();
mEditor.maybeFireScheduledRestartInputForSetText();
}
}
这里主要看checkForRelayout()这个方法,继续看
private void checkForRelayout() {
// If we have a fixed width, we can just swap in a new text layout
// if the text height stays the same or if the view height is fixed.
if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT
|| (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))
&& (mHint == null || mHintLayout != null)
&& (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {
// Static width, so try making a new text layout.
int oldht = mLayout.getHeight();
int want = mLayout.getWidth();
int hintWant = mHintLayout == null ? 0 : mHintLayout.getWidth();
/*
* No need to bring the text into view, since the size is not
* changing (unless we do the requestLayout(), in which case it
* will happen at measure).
*/
makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,
mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),
false);
//不是跑马灯样式的文本
if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {
// In a fixed-height view, so use our new text layout.
//高度是一个精确值比如:android:layout_height="100dp"
// 这里不会走requestLayout()
```
if (mLayoutParams.height != LayoutParams.WRAP_CONTENT
&& mLayoutParams.height != LayoutParams.MATCH_PARENT) {
autoSizeText();
invalidate();
return;
}
// Dynamic height, but height has stayed the same,
// so use our new text layout.
//新文本的高和原来文本的高度一致 这里不会走requestLayout()
if (mLayout.getHeight() == oldht
&& (mHintLayout == null || mHintLayout.getHeight() == oldht)) {
autoSizeText();
invalidate();
return;
}
}
// We lose: the height has changed and we have a dynamic height.
// Request a new view layout using our new text layout.
requestLayout();
invalidate();
} else {
// Dynamic width, so we have no choice but to request a new
// view layout with a new text layout.
nullLayouts();
requestLayout();
invalidate();
}
}
这里我们可以看的出来,如果TextView的width属性不是wrap_content并且高度不会发生变化,那么就不会走requestLayout,TextView的高度不会发生变化有两种情况,一种是TextView的height被设置成一个精确值比如:android:layout_height="100dp" ,另外一种就是新文本的高度和原来的文本高度一致,这两种情况都只会调用invalidate方法。