Android ondraw原理,Android 重学系列 View的绘制流程(五) onDraw

前言

之前已经和大家聊了onLayout的流程,本文将会继续聊一聊onDraw中做了什么?本文将集中关注软件渲染,关于Canvas的api源码解析暂时不会在本文聊,会专门开一个Skia源码解析进行分析。

正文

performTravel的方法走完onMeasure和onLayout流程后会走到下面这段代码段。

文件:/frameworks/base/core/java/android/view/ViewRootImpl.java

if (mFirst) {

if (sAlwaysAssignFocus || !isInTouchMode()) {

if (mView != null) {

if (!mView.hasFocus()) {

mView.restoreDefaultFocus();

} else {

...

}

}

} else {

View focused = mView.findFocus();

if (focused instanceof ViewGroup

&& ((ViewGroup) focused).getDescendantFocusability()

== ViewGroup.FOCUS_AFTER_DESCENDANTS) {

focused.restoreDefaultFocus();

}

}

}

final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;

final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;

final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;

if (regainedFocus) {

mLostWindowFocus = false;

} else if (!hasWindowFocus && mHadWindowFocus) {

mLostWindowFocus = true;

}

if (changedVisibility || regainedFocus) {

boolean isToast = (mWindowAttributes == null) ? false

: (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);

...

}

mFirst = false;

mWillDrawSoon = false;

mNewSurfaceNeeded = false;

mActivityRelaunched = false;

mViewVisibility = viewVisibility;

mHadWindowFocus = hasWindowFocus;

if (hasWindowFocus && !isInLocalFocusMode()) {

final boolean imTarget = WindowManager.LayoutParams

.mayUseInputMethod(mWindowAttributes.flags);

if (imTarget != mLastWasImTarget) {

mLastWasImTarget = imTarget;

InputMethodManager imm = InputMethodManager.peekInstance();

if (imm != null && imTarget) {

imm.onPreWindowFocus(mView, hasWindowFocus);

imm.onPostWindowFocus(mView, mView.findFocus(),

mWindowAttributes.softInputMode,

!mHasHadWindowFocus, mWindowAttributes.flags);

}

}

}

在进入onDraw的流程之前,会先处理焦点。这个过程中可以分为2大步骤:

1.如果是第一次渲染,则说明之前的宽高都是都为0.在requestFocus方法中会有这个判断把整个焦点集中拦截下来:

private boolean canTakeFocus() {

return ((mViewFlags & VISIBILITY_MASK) == VISIBLE)

&& ((mViewFlags & FOCUSABLE) == FOCUSABLE)

&& ((mViewFlags & ENABLED_MASK) == ENABLED)

&& (sCanFocusZeroSized || !isLayoutValid() || hasSize());

}

而在每一次onMeasure之前,都会尝试集中一次焦点的遍历。其中requestFocusNoSearch方法中,如果没有测量过就会直接返回false。因为每一次更换焦点或者集中焦点都可能伴随着如背景drawable,statelistDrawable等切换。没有测量过就没有必要做这无用功(详情请看View的绘制流程(三) onMeasure

)。

因此此时为了弥补之前拒绝焦点的行为,会重新进行一次restoreDefaultFocus的行为进行requestFocus处理。

2.如果存在窗体焦点,同时不是打开了FLAG_LOCAL_FOCUS_MODE标志(这是一种特殊情况,一般打上这个标志位只有在startingWindow的快照中才会有,startingWindow具体是什么可以看看WMS在Activity启动中的职责 添加窗体(三))。

则会调用InputMethodManager的onPostWindowFocus方法启动带了android.view.InputMethod这个action的软键盘服务。详细的这里暂时不展开讨论。

onDraw流程

if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {

reportNextDraw();

}

boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;

if (!cancelDraw && !newSurface) {

if (mPendingTransitions != null && mPendingTransitions.size() > 0) {

for (int i = 0; i < mPendingTransitions.size(); ++i) {

mPendingTransitions.get(i).startChangingAnimations();

}

mPendingTransitions.clear();

}

performDraw();

} else {

if (isViewVisible) {

scheduleTraversals();

} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {

for (int i = 0; i < mPendingTransitions.size(); ++i) {

mPendingTransitions.get(i).endChangingAnimations();

}

mPendingTransitions.clear();

}

}

mIsInTraversal = false;

1.判断到如果是第一次调用draw方法,则会调用reportNextDraw。

private void reportNextDraw() {

if (mReportNextDraw == false) {

drawPending();

}

mReportNextDraw = true;

}

void drawPending() {

mDrawsNeededToReport++;

}

能看到实际上就是设置mReportNextDraw为true。我们回顾一下前两个流程mReportNextDraw参与了标志位的判断。在执行onMeasure和onLayout有两个大前提,一个是mStop为false,一个是mReportNextDraw为true。只要满足其一就会执行。

这么做的目的只有一个,保证调用一次onDraw方法。为什么会这样呢?performDraw是整个Draw流程的入口。然而在这个入口,必须要保证cancelDraw为false以及newSurface为false。

注意,如果是第一次渲染因为会添加进新的Surface,此时newSurface为true(可以看View的绘制流程(二) 绘制的准备)。所以会走到下面的分之,如果串口可见则调用scheduleTraversals执行下一次Loop的绘制流程。否则判断是否有需要执行的LayoutTransitions layout动画就执行了。

因此第一次是不会走到onDraw,是从第二次Looper之后View的绘制流程才会执行onDraw。

我们继续关注performDraw的逻辑。

ViewRootImpl performDraw

private void performDraw() {

if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {

return;

} else if (mView == null) {

return;

}

final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw;

mFullRedrawNeeded = false;

mIsDrawing = true;

Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");

boolean usingAsyncReport = false;

if (mReportNextDraw && mAttachInfo.mThreadedRenderer != null

&& mAttachInfo.mThreadedRenderer.isEnabled()) {

usingAsyncReport = true;

mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {

pendingDrawFinished();

});

}

try {

boolean canUseAsync = draw(fullRedrawNeeded);

if (usingAsyncReport && !canUseAsync) {

mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);

usingAsyncReport = false;

}

} finally {

mIsDrawing = false;

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

}

if (mAttachInfo.mPendingAnimatingRenderNodes != null) {

final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();

for (int i = 0; i < count; i++) {

mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();

}

mAttachInfo.mPendingAnimatingRenderNodes.clear();

}

if (mReportNextDraw) {

mReportNextDraw = false;

if (mWindowDrawCountDown != null) {

try {

mWindowDrawCountDown.await();

} catch (InterruptedException e) {

Log.e(mTag, "Window redraw count down interrupted!");

}

mWindowDrawCountDown = null;

}

if (mAttachInfo.mThreadedRenderer != null) {

mAttachInfo.mThreadedRenderer.setStopped(mStopped);

}

if (mSurfaceHolder != null && mSurface.isValid()) {

SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);

SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();

sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);

} else if (!usingAsyncReport) {

if (mAttachInfo.mThreadedRenderer != null) {

mAttachInfo.mThreadedRenderer.fence();

}

pendingDrawFinished();

}

}

}

我们把整个流程抽象出来实际上就是可以分为如下几个步骤:

对于软件渲染:

1.调用draw方法,遍历View的层级。

2.如果Surface是生效的,则在SurfaceHolder.Callback的surfaceRedrawNeededAsync回调中调用pendingDrawFinished。

3.如果是强制同步渲染,则会直接调用pendingDrawFinished。

对于硬件渲染:

1.调用draw方法,遍历View的层级。

2.通过监听mThreadedRenderer的setFrameCompleteCallback回调执行pendingDrawFinished方法。

我们先关注软件渲染的流程。也就是draw和pendingDrawFinished。

ViewRootImpl draw

private boolean draw(boolean fullRedrawNeeded) {

Surface surface = mSurface;

if (!surface.isValid()) {

return false;

}

if (!sFirstDrawComplete) {

synchronized (sFirstDrawHandlers) {

sFirstDrawComplete = true;

final int count = sFirstDrawHandlers.size();

for (int i = 0; i< count; i++) {

mHandler.post(sFirstDrawHandlers.get(i));

}

}

}

scrollToRectOrFocus(null, false);

if (mAttachInfo.mViewScrollChanged) {

mAttachInfo.mViewScrollChanged = false;

mAttachInfo.mTreeObserver.dispatchOnScrollChanged();

}

boolean animating = mScroller != null && mScroller.computeScrollOffset();

final int curScrollY;

if (animating) {

curScrollY = mScroller.getCurrY();

} else {

curScrollY = mScrollY;

}

if (mCurScrollY != curScrollY) {

mCurScrollY = curScrollY;

fullRedrawNeeded = true;

if (mView instanceof RootViewSurfaceTaker) {

((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);

}

}

final float appScale = mAttachInfo.mApplicationScale;

final boolean scalingRequired = mAttachInfo.mScalingRequired;

final Rect dirty = mDirty;

if (mSurfaceHolder != null) {

dirty.setEmpty();

if (animating && mScroller != null) {

mScroller.abortAnimation();

}

return false;

}

if (fullRedrawNeeded) {

mAttachInfo.mIgnoreDirtyState = true;

dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));

}

mAttachInfo.mTreeObserver.dispatchOnDraw();

int xOffset = -mCanvasOffsetX;

int yOffset = -mCanvasOffsetY + curScrollY;

final WindowManager.LayoutParams params = mWindowAttributes;

final Rect surfaceInsets = params != null ? params.surfaceInsets : null;

if (surfaceInsets != null) {

xOffset -= surfaceInsets.left;

yOffset -= surfaceInsets.top;

dirty.offset(surfaceInsets.left, surfaceInsets.right);

}

...

mAttachInfo.mDrawingTime =

mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;

boolean useAsyncReport = false;

if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {

if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {

boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;

mInvalidateRootRequested = false;

mIsAnimating = false;

if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {

mHardwareYOffset = yOffset;

mHardwareXOffset = xOffset;

invalidateRoot = true;

}

if (invalidateRoot) {

mAttachInfo.mThreadedRenderer.invalidateRoot();

}

dirty.setEmpty();

final boolean updated = updateContentDrawBounds();

if (mReportNextDraw) {

mAttachInfo.mThreadedRenderer.setStopped(false);

}

if (updated) {

requestDrawWindow();

}

useAsyncReport = true;

final FrameDrawingCallback callback = mNextRtFrameCallback;

mNextRtFrameCallback = null;

mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback);

} else {

if (mAttachInfo.mThreadedRenderer != null &&

!mAttachInfo.mThreadedRenderer.isEnabled() &&

mAttachInfo.mThreadedRenderer.isRequested() &&

mSurface.isValid()) {

try {

mAttachInfo.mThreadedRenderer.initializeIfNeeded(

mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);

} catch (OutOfResourcesException e) {

handleOutOfResourcesException(e);

return false;

}

mFullRedrawNeeded = true;

scheduleTraversals();

return false;

}

if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,

scalingRequired, dirty, surfaceInsets)) {

return false;

}

}

}

if (animating) {

mFullRedrawNeeded = true;

scheduleTraversals();

}

return

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值