Android Scroll in detail (iii): Android drawing process detailed

Source: Internet
Author: User

Ztelur
Contact information: Segmentfault,csdn,github

Please indicate the original author, the source of the article, the link, the copyright belongs to the original author.

This article is the last article in the Android Scroll series, mainly on the Android view drawing mechanism, because this series of articles are related to the view scrolling, so this article from the View content scrolling perspective to comb the view drawing process.
? If you have not read this series of articles or do not know the relevant knowledge, please read the article:

    • Android Motionevent Detailed
    • Android Scroll Details (i): basic knowledge
    • Android Scroll Detailed (ii): Overscroller combat

In order to save everyone's time, the main content of this article is as follows:

    • ScrollerRelated mechanisms.
    • mScrollXand mScrollY How the view content is affected.
    • The Android view draws logic, including related APIs and Canvas related operations.
everything Scroller starts with the use of

Using the Scroller instance code, the next tutorial is how scroller and Computescroll are called.
? In the second installment of the series, we have specifically learned Scroller how to use it. Through Scroller the fling and of the View computeScroll mates, realize the view scrolling effect. The instance code is as follows

.....           mScroller.fling(0,getScrollY(),0,speed,0,0,-500,10000)    invalidate();    .....    @Override    publicvoidcomputeScroll() {            if (mScroller.computeScrollOffset()) {                        scrollTo(mScroller.getCurrX(),                        mScroller.getCurrY());               postInvalidate();            }    }

? This article takes you through the principles and mechanisms behind this code.

invalidate's path to seek the Father

? This section mainly analyzes the principle of call invalidate to execution in view ViewRoot , the performTraversals Android view architecture is not very familiar with the students can first read the "Android view architecture in detail."

? Let View 's look at the code in the first invalidate .

     Public void Invalidate() {Invalidate (true); }voidInvalidateBooleanInvalidatecache) {invalidateinternal (0,0, Mright-mleft, Mbottom-mtop, Invalidatecache,true); }voidInvalidateinternal (intLintTintRintBBooleanInvalidatecache,BooleanFullinvalidate) {...if//drawn and Has_bounds are set to 1, indicating that the last UI drawing for the execution of the request has been completed, you can request execution again            if(Mprivateflags & (Pflag_drawn | pflag_has_bounds) = = (Pflag_drawn | Pflag_has_bounds) | |                    (Invalidatecache && (mprivateflags & pflag_drawing_cache_valid) = = Pflag_drawing_cache_valid) || (Mprivateflags & pflag_invalidated)! = pflag_invalidated | | (Fullinvalidate && isopaque ()! = Mlastisopaque)) {if(fullinvalidate)                    {mlastisopaque = Isopaque ();                Mprivateflags &= ~pflag_drawn; } mprivateflags |= Pflag_dirty;if(Invalidatecache) {//Whether to invalidate the view cacheMprivateflags |= pflag_invalidated;                Mprivateflags &= ~pflag_drawing_cache_valid; }//Propagate The damage rectangle to the parent view.                FinalAttachinfo ai = mattachinfo;FinalViewparent p = mparent;//through viewparent, if the current view is the top-level view or Decorview view, then its                //mparent is the Viewroot object, so it is implemented by Viewroot objects.                 if(P! =NULL&& ai! =NULL&& L < R && T < b) {FinalRect damage = Ai.mtmpinvalrect;                    Damage.set (L, T, R, b); P.invalidatechild ( This, damage);//todo: This is the subject of invalidate execution}                .....            } }

? We can see that the call invalidate() causes the entire view to refresh and the cache is refreshed.
? Then we'll look at invalidateInternal the code in detail. Let's take a look at if the judgment condition of the sentence first.

    if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)            || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)            || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED            || (fullInvalidate && isOpaque() != mLastIsOpaque))
    • When mPrivateFlags the FLAG_DRAWN and FLAG_HAS_BOUNDS bit is set to 1 o'clock, the UI drawing that was last requested to execute has completed, you can request a redraw again. Bit will be set to 1 in the FLAG_DRAWN draw function, and will be 1 in the FLAG_HAS_BOUNDS setFrame function.
    • mPrivateFlagsPFLAG_DRAWING_CACHE_VALIDIndicates whether the cached view cache is valid, and if it is valid and invalidateCache true, a redraw can be requested.
    • The other two Boolean judgments of the specific meaning of the analysis is not clear, we are interested in your own research.
      ? Then set mPrivateFlags PFLAG_DIRTY to 1. And if it is to flush the cache, PFLAG_INVALIDATED set the bit to 1, and PFLAG_DRAWING_CACHE_VALID set the bit to 0, this step and the previous if judgement in the last two Boolean judgments correspond, visible, if there is already a invalidate set of the above two flag bits, then the next invalidate No action will be made.
      Then, call the Invalidatechild function of the Viewparent interface, in the "Android View architecture in detail", we already know ViewGroup and ViewRoot all implement the above interface, then, according to the Android View tree structure, ViewGroup The corresponding method of the call will be called.
 Public Final void Invalidatechild(View Child,FinalRect Dirty) {viewparent parent = This;FinalAttachinfo attachinfo = Mattachinfo;if(Attachinfo! =NULL) {        ....//While always upward recursionDo {.... parent = parent.invalidatechildinparent (location, dirty); ....        } while(Parent! =NULL); }} PublicViewparentinvalidatechildinparent(Final int[] location,FinalRect Dirty) {if((Mprivateflags & pflag_drawn) = = Pflag_drawn | | (Mprivateflags & pflag_drawing_cache_valid) = = Pflag_drawing_cache_valid) {if(Mgroupflags & (Flag_optimize_invalidate | Flag_animation_done))! = Flag_optimize_invalidate) {...returnMparent; }Else{            .....returnMparent; }    }return NULL;}

? Through the code we can see ViewGroup the invalidateChild function through the loop constantly call its parent view, invalidateChildInParent and we know ViewRoot is DecorView the parent view, that ViewRoot is, the root of the Android view tree structure. So, the end result ViewRoot invalidateChildInParent will be called.

  //In ViewGroup invalidatechildinparent while loop, always call here, and then call Invalidatechild     PublicViewparentinvalidatechildinparent(Final int[] location,FinalRect dirty) {Invalidatechild (NULL, dirty);return NULL; } Public void Invalidatechild(View child, Rect Dirty) {//Check thread first, must be main threadCheckthread (); .....//If Mwilldrawsoon is true then there is already a do_traversal message in the message queue .    if(!mwilldrawsoon) {//Call this directlyScheduletraversals (); }}

? Finally, in ViewRoot the invalidateChild function, called, the scheduleTraversals view is opened to redraw the journey.

We've all been ViewRoot cheated.

?ViewRoot is the root node of the Android view tree structure, and it implements the ViewParent interface, which is DecorView the parent view. Then everyone will think it is a View bar. Then we'll be fooled by it!! ViewRootis essentially a Handler , we can see scheduleTraversals performTraversals the principle to know.

publicvoidscheduleTraversals() {    if (!mTraversalScheduled) {        true;        sendEmptyMessage(DO_TRAVERSAL);    }}

? in scheduleTraversals , ViewRoot just send yourself an DO_TRAVERSAL empty message.

  @Override  public  void  handlemessage  (Message msg) {switch  (msg.what) {.... case  do_traversal: //this is where handle handles travel information  if  (mprofile) {debug.startmethodtracing ( "Viewroot" );            } performtraversals (); if  (Mprofile)                {debug.stopmethodtracing ();            Mprofile = false ;            } break ;    .....        } }

? Then we looked at the handleMessage method and found that the function was called when it was processed DO_TRAVERSAL ViewRoot performTraversals .
In performTraversals , the view is going to be measure,layout, and draw three big steps, space is limited, we only study drawing related mechanism here.
?ViewRoot In the performTraversals call of their own draw method, see, ViewRoot camouflage is quite like, even draw methods have. But we will find that in the method, we draw ViewRoot actually only invoke the method of our own mView member variables draw , and we all know that, that is, the mView DecorView drawing process came to the root node of the real view view.

Canvas for everyone to draw

? Next, we'll take a formal look at the Android drawing mechanism, and we'll follow the tree-like structure of the Android view to analyze the drawing principle.

? The first is DecorView the drawing-related function. In ViewRoot the draw method, directly called the DecorView draw(Canvas canvas) function, we know DecorView is FrameLayout the subclass, its draw(Canvas canvas) function is inherited from the View . So let's look View at the draw(Canvas canvas) method first.

    //Http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/ View/view.java#view     Public void Draw(Canvas canvas) {             ......../* * Draw traversal performs several drawing steps which must be executed * in the appropriate Order: * * 1. Draw the background * 2. If necessary, save the canvas ' layers to prepare for fading * 3. Draw View ' s content * 4. Draw Children * 5. If necessary, draw the fading edges and restore layers * 6. Draw Decorations (scrollbars for instance) */            //Step 1, draw the background, if needed            if(!dirtyopaque)            {drawbackground (canvas); }            .......//Step 2, Save the canvas ' layers.......//Step 3, draw the content            if(!dirtyopaque) OnDraw (canvas);//Step 4, Draw the childrenDispatchdraw (canvas);//Step 5, draw the fade effect and restore layers.......if(Drawtop) {Matrix.setscale (1, Fadeheight * topfadestrength);                Matrix.posttranslate (left, top);                Fade.setlocalmatrix (matrix);                P.setshader (Fade);            Canvas.drawrect (left, top, right, top + length, p); }            .....//Step 6, Draw decorations (scrollbars)Ondrawscrollbars (canvas); ......        }

About the parts of the view, which I have already described in the previous article, please consult the articles or other materials by yourself who are not familiar with this section. As we can see from the above code, View the dispatchDraw function is called, which is the method of distributing the drawing instructions and related data to the child view. In View , the above function is an empty function, but the ViewGroup function is implemented.

    protected void Dispatchdraw(Canvas canvas) {        ....FinalArraylist<view> preorderedlist = usingrendernodeproperties?NULL: Buildorderedchildlist ();Final BooleanCustomorder = Preorderedlist = =NULL&& ischildrendrawingorderenabled (); for(inti =0; i < Childrencount; i++) {intChildindex = Customorder? Getchilddrawingorder (Childrencount, i): i;FinalView Child = (Preorderedlist = =NULL)                    ? Children[childindex]: Preorderedlist.get (Childindex);if((Child.mviewflags & visibility_mask) = = VISIBLE | | child.getanimation ()! =NULL) {//Here DrawchildMore |= drawchild (canvas, Child, drawingtime); }        }        ....    }protected Boolean Drawchild(Canvas canvas, View child,LongDrawingtime) {//This calls the child's draw method instead of the draw (canvas) method!!!!!         returnChild.draw (Canvas, This, drawingtime); }

? We can see from the above code that we have ViewGroup called our own sub-view draw method, and it is important to note that this draw and the previous draw method are not the same method, their parameters are different. So, we go to View the source code again, and see what this draw method did.

    BooleanDraw (canvas canvas, viewgroup parent,LongDrawingtime) {....//Perform calculation scrolling        if(!hasdisplaylist)            {Computescroll ();            SX = MSCROLLX;        sy = mscrolly; }        ...//translation is done here.         if(Offsetforscroll)        {canvas.translate (MLEFT-SX, Mtop-sy); }        .....if(!layerrendered) {if(!hasdisplaylist) {//Fast path for layouts with no backgrounds            if((Mprivateflags & pflag_skip_draw) = = Pflag_skip_draw)              {mprivateflags &= ~pflag_dirty_mask;            Dispatchdraw (canvas); }Else{//Call draw hereDraw (canvas);        }          }                 ......        } ......    }

? First, we find that the computeScroll method is called in which to calculate the new mScrollX and mScrollY then translate the canvas, resulting in the content panning effect.
? Then we find PFLAG_SKIP_DRAW that through the flag bit judgment, some view is called directly dispatchDraw function, stating that it does not need to draw the content, and some view is to call their own draw methods. We should all know that the ViewGroup default is not to draw the content, we generally call the setNotWillDraw method to let it draw its own content, by invoking setNotWillDraw the method, will cause the PFLAG_SKIP_DRAW bit to be set to 1, so that it can draw its own content.
Analysis here, we will find that the draw function is constantly being called along the Android View tree structure, knowing that all views are drawn.

to connect everything together, Computescroll.

Read here that you should have a basic understanding of the Android view drawing process, so let's take a look at the beginning of the article. In the computeScroll method, we call the postInvalidate method, what is the purpose?
In fact, in the computeScroll middle does not postInvalidate seem to be able to achieve the correct effect, specific reasons I do not know, guess should be Android Auto Refresh interface can replace postInvalidate the effect bar. If the students know the specific reasons, please tell me.
? In "Android Scroll (i): Basics", we've talked about
postInvalidateIn fact, it is called invalidate , then the whole process is connected, mScrollX and mScrollY each cycle will change a little, and then lead to the interface scrolling, resulting in an interface scroll effect.

PostScript

? The series of articles on Android Scroll is over and I hope you will learn useful knowledge from it. If there is any mistake or misunderstanding, please notify me in time. Thank you, readers and classmates.

Http://www.cppblog.com/fwxjj/archive/2013/01/13/197231.html
http://blog.csdn.net/luoshengyang/article/details/8372924

Android Scroll in detail (iii): Android drawing process detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.