为什么调用 invalidate() 会重新执行 onDraw() ?
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
...
public void invalidate() {
invalidate(true);
}
public void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
...
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
}
...
}
View 「 invalidate() -> invalidate(true) -> invalidateInternal() 」最终调用到
ViewGroup 「 invalidateChild() 」
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
...
public final void invalidateChild(View child, final Rect dirty) {
...
do {
View view = null;
if (parent instanceof View) {
view = (View) parent;
}
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
} else if (parent instanceof ViewRootImpl) {
((ViewRootImpl) parent).mIsAnimating = true;
}
}
// If the parent is dirty opaque or not dirty, mark it dirty with the opaque
// flag coming from the child that initiated the invalidate
if (view != null) {
if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
}
}
parent = parent.invalidateChildInParent(location, dirty);
if (view != null) {
// Account for transform on current parent
Matrix m = view.getMatrix();
if (!m.isIdentity()) {
RectF boundingRect = attachInfo.mTmpTransformRect;
boundingRect.set(dirty);
m.mapRect(boundingRect);
dirty.set((int) Math.floor(boundingRect.left),
(int) Math.floor(boundingRect.top),
(int) Math.ceil(boundingRect.right),
(int) Math.ceil(boundingRect.bottom));
}
}
while (parent != null);
}
}
do while 循环调用 invalidateChildInParent(),里层的 View 调用的是
ViewGroup.invalidateChildInParent() 方法,最外层 View 也就是 ViewRootImpl,掉用 ViewRootImpl.invalidateChildInParent()
为什么在子线程更新 UI 会报错 ?
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
public ViewRootImpl(Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
...
mThread = Thread.currentThread();//主线程
...
}
mThread( 主线程 ) 在 ViewRootImpl 构造方法中初始化,当我们在子线程更新 UI 时,Thread.currentThread() 为子线程,所以在子线程更新 UI 会报错。
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
...
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
checkThread();
...
invalidateRectOnScreen(dirty);
}
private void invalidateRectOnScreen(Rect dirty) {
final Rect localDirty = mDirty;
// Add the new dirty rect to the current one
localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
// Intersect with the bounds of the window to skip
// updates that lie outside of the visible region
final float appScale = mAttachInfo.mApplicationScale;
final boolean intersected = localDirty.intersect(0, 0,
(int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
if (!intersected) {
localDirty.setEmpty();
}
if (!mWillDrawSoon && (intersected || mIsAnimating)) {
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
private void performTraversals() {
...
performMeasure();
performLayout();
performDraw();
...
}
private void performDraw() {
...
boolean canUseAsync = draw(fullRedrawNeeded);
...
}
private boolean draw(boolean fullRedrawNeeded) {
...
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
scalingRequired, dirty, surfaceInsets)) {
return false;
}
...
}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
...
mView.draw(canvas);
...
}
}
ViewRootImpl 「invalidateChildInParent() -> invalidateRectOnScreen() -> scheduleTraversals() -> doTraversal() -> performTraversals() -> performDraw() -> draw() -> drawSoftware()」最终调用到 View.draw()
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
...
public void draw(Canvas canvas) {
...
drawBackground(canvas);
...
onDraw(canvas);//绘制自己
dispatchDraw(canvas);//绘制 children
}
...
}
invalidate.jpg
网友评论