darklord
darklord

Reputation: 5167

Android when onDraw is called?

It is said that onDraw() will be called when invalidate() is called. However, when I look at the android source code. I didn't find where the onDraw() gets called in invalidate(). So I am still confused about how the onDraw() method is called for a view. Who can help me figuring this out?

Upvotes: 2

Views: 7375

Answers (6)

darklord
darklord

Reputation: 5167

I have to call setWillNotDraw(false). It is set to true by default for all subclasses of ViewGroup.

Upvotes: 1

Raghunandan
Raghunandan

Reputation: 133560

Drawing

Drawing is handled by walking the tree and rendering each view that intersects the invalid region. Because the tree is traversed in-order, this means that parents will draw before (i.e., behind) their children, with siblings drawn in the order they appear in the tree. If you set a background drawable for a View, then the View will draw it for you before calling back to its onDraw() method. Note that the framework will not draw views that are not in the invalid region. To force a view to draw, call invalidate().

Invalidate the whole view. If the view is visible, onDraw(android.graphics.Canvas) will be called at some point in the future. This must be called from a UI thread. To call from a non-UI thread, call postInvalidate().

10340    public void invalidate() {
10341        invalidate(true);
10342    }

Source

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/view/View.java#View.invalidate%28boolean%29

This is where the invalidate() work actually happens. A full invalidate() causes the drawing cache to be invalidated, but this function can be called with invalidateCache set to false to skip that invalidation step for cases that do not need it (for example, a component that remains at the same dimensions with the same content).

Parameters:

invalidateCache Whether the drawing cache for this view should be invalidated as well. This is usually true for a full invalidate, but may be set to false if the View's contents or dimensions have not changed.

10354
10355    void invalidate(boolean invalidateCache) {
10356        if (skipInvalidate()) {
10357            return;
10358        }
10359        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
10360                (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||
10361                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {
10362            mLastIsOpaque = isOpaque();
10363            mPrivateFlags &= ~PFLAG_DRAWN;
10364            mPrivateFlags |= PFLAG_DIRTY;
10365            if (invalidateCache) {
10366                mPrivateFlags |= PFLAG_INVALIDATED;
10367                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
10368            }
10369            final AttachInfo ai = mAttachInfo;
10370            final ViewParent p = mParent;
10371            //noinspection PointlessBooleanExpression,ConstantConditions
10372            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
10373                if (p != null && ai != null && ai.mHardwareAccelerated) {
10374                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
10375                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
10376                    p.invalidateChild(this, null);
10377                    return;
10378                }
10379            }
10380
10381            if (p != null && ai != null) {
10382                final Rect r = ai.mTmpInvalRect;
10383                r.set(0, 0, mRight - mLeft, mBottom - mTop);
10384                // Don't call invalidate -- we don't want to internally scroll
10385                // our own bounds
10386                p.invalidateChild(this, r);
10387            }
10388        }
10389    }

Upvotes: 8

maclir
maclir

Reputation: 3309

According to View | Android Developers:

Drawing is handled by walking the tree and rendering each view that intersects the invalid region. Because the tree is traversed in-order, this means that parents will draw before (i.e., behind) their children, with siblings drawn in the order they appear in the tree. If you set a background drawable for a View, then the View will draw it for you before calling back to its onDraw() method.

Note that the framework will not draw views that are not in the invalid region.

To force a view to draw, call invalidate().

Which mean when the UI thread gets to it (the invalid region) it will call onDraw() for that region.

Upvotes: 0

Dulanga
Dulanga

Reputation: 1346

Take a look at this post. This explains you exactly when onDraw() will be called.

Upvotes: 0

DeeV
DeeV

Reputation: 36035

Invalidate won't call onDraw() directly. It schedules a draw pass to the system which says that the Views need to draw at some point in the future which is usually almost immediately. If the UI thread is blocked, it can take some time though.

Upvotes: 8

Jainendra
Jainendra

Reputation: 25143

A View's onDraw() is called when:

  1. The view is initially drawn
  2. Whenever invalidate() is called on the view

Upvotes: -1

Related Questions