Android View刷新机制实例分析
本文实例讲述了AndroidView刷新机制。分享给大家供大家参考,具体如下:
一、总体说明
在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成。
二、代码分析
1).ViewGroup的addView方法,理解参数的意义和传递
invalidate调用父类View的方法
addViewInner方法主要做的事情是
view的dispatchAttachedToWindow(AttachInfoinfo,intvisibility)方法
1).View的invalidate方法,这是一个从下第向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新
Rect做交集。
voidinvalidate(booleaninvalidateCache){
if(ViewDebug.TRACE_HIERARCHY){
ViewDebug.trace(this,ViewDebug.HierarchyTraceType.INVALIDATE);
}
if(skipInvalidate()){
return;
}
if((mPrivateFlags&(DRAWN|HAS_BOUNDS))==(DRAWN|HAS_BOUNDS)||
(invalidateCache&&(mPrivateFlags&DRAWING_CACHE_VALID)==DRAWING_CACHE_VALID)||
(mPrivateFlags&INVALIDATED)!=INVALIDATED||isOpaque()!=mLastIsOpaque){
mLastIsOpaque=isOpaque();
mPrivateFlags&=~DRAWN;
mPrivateFlags|=DIRTY;
if(invalidateCache){
mPrivateFlags|=INVALIDATED;
mPrivateFlags&=~DRAWING_CACHE_VALID;
}
finalAttachInfoai=mAttachInfo;
finalViewParentp=mParent;
//noinspectionPointlessBooleanExpression,ConstantConditions
if(!HardwareRenderer.RENDER_DIRTY_REGIONS){
if(p!=null&&ai!=null&&ai.mHardwareAccelerated){
//fast-trackforGL-enabledapplications;justinvalidatethewholehierarchy
//withanulldirtyrect,whichtellstheViewAncestortoredraweverything
p.invalidateChild(this,null);
return;
}
}
if(p!=null&&ai!=null){
finalRectr=ai.mTmpInvalRect;
r.set(0,0,mRight-mLeft,mBottom-mTop);
//Don'tcallinvalidate--wedon'twanttointernallyscroll
//ourownbounds
p.invalidateChild(this,r);//调用子类的方法完成
}
}
}
2)ViewGrop的invalidateChild方法
publicfinalvoidinvalidateChild(Viewchild,finalRectdirty){
ViewParentparent=this;
finalAttachInfoattachInfo=mAttachInfo;
if(attachInfo!=null){
finalint[]location=attachInfo.mInvalidateChildLocation;
//需要刷新的子View的位置
location[CHILD_LEFT_INDEX]=child.mLeft;
location[CHILD_TOP_INDEX]=child.mTop;
//Ifthechildisdrawingananimation,wewanttocopythisflagonto
//ourselvesandtheparenttomakesuretheinvalidaterequestgoesthrough
finalbooleandrawAnimation=(child.mPrivateFlags&DRAW_ANIMATION)==DRAW_ANIMATION;
//Checkwhetherthechildthatrequeststheinvalidateisfullyopaque
finalbooleanisOpaque=child.isOpaque()&&!drawAnimation&&child.getAnimation()!=null;
//Markthechildasdirty,usingtheappropriateflag
//Makesurewedonotsetbothflagsatthesametime
finalintopaqueFlag=isOpaque?DIRTY_OPAQUE:DIRTY;
do{
Viewview=null;
if(parentinstanceofView){
view=(View)parent;
}
if(drawAnimation){
if(view!=null){
view.mPrivateFlags|=DRAW_ANIMATION;
}elseif(parentinstanceofViewRoot){
((ViewRoot)parent).mIsAnimating=true;
}
}
//Iftheparentisdirtyopaqueornotdirty,markitdirtywiththeopaque
//flagcomingfromthechildthatinitiatedtheinvalidate
if(view!=null&&(view.mPrivateFlags&DIRTY_MASK)!=DIRTY){
view.mPrivateFlags=(view.mPrivateFlags&~DIRTY_MASK)|opaqueFlag;
}
parent=parent.invalidateChildInParent(location,dirty);
}while(parent!=null);
}
}
publicViewParentinvalidateChildInParent(finalint[]location,finalRectdirty){
if((mPrivateFlags&DRAWN)==DRAWN){
if((mGroupFlags&(FLAG_OPTIMIZE_INVALIDATE|FLAG_ANIMATION_DONE))!=
FLAG_OPTIMIZE_INVALIDATE){
//根据父View的位置,偏移刷新区域
dirty.offset(location[CHILD_LEFT_INDEX]-mScrollX,location[CHILD_TOP_INDEX]-mScrollY);
finalintleft=mLeft;
finalinttop=mTop;
//计算实际可刷新区域
if(dirty.intersect(0,0,mRight-left,mBottom-top)||
(mPrivateFlags&DRAW_ANIMATION)==DRAW_ANIMATION){
mPrivateFlags&=~DRAWING_CACHE_VALID;
location[CHILD_LEFT_INDEX]=left;
location[CHILD_TOP_INDEX]=top;
returnmParent;
}
}else{
mPrivateFlags&=~DRAWN&~DRAWING_CACHE_VALID;
location[CHILD_LEFT_INDEX]=mLeft;
location[CHILD_TOP_INDEX]=mTop;
dirty.set(0,0,mRight-location[CHILD_LEFT_INDEX],
mBottom-location[CHILD_TOP_INDEX]);
returnmParent;
}
}
returnnull;
}
这个向上回溯的过程直到ViewRoot那里结束,由ViewRoot对这个最终的刷新区域做刷新
ViewRoot.java
publicvoidinvalidateChild(Viewchild,Rectdirty){
}
由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。
调用流程:
mView.draw()开始绘制,draw()方法实现的功能如下:
1、绘制该View的背景
2、为显示渐变框做一些准备操作(见5,大多数情况下,不需要改渐变框)
3、调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
4、调用dispatchDraw()方法绘制子视图(如果该View类型不为ViewGroup,即不包含子视图,不需要重载该
方法)值得说明的是,ViewGroup类已经为我们重写了dispatchDraw()的功能实现,应用程序一般不需要重写该
方法,但可以重载父类函数实现具体的功能。
4.1dispatchDraw()方法内部会遍历每个子视图,调用drawChild()去重新回调每个子视图的draw()方法(注意,这个地方“需要重绘”的视图才会调用draw()方法)。值得说明的是,ViewGroup类已经为我们重写了dispatch
Draw()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。
更多关于Android相关内容感兴趣的读者可查看本站专题:《Android开发入门与进阶教程》、《Android多媒体操作技巧汇总(音频,视频,录音等)》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》
希望本文所述对大家Android程序设计有所帮助。