Android 滑动绘制流程探究 系统是如何提高滑动性能?
页面在滑动的过程中如果要感觉流程,必须要达到每秒60帧,当然多了也是浪费,因为那样人眼也是无法区分开来的。Android 图形绘制通过VSYNC机制来保证每秒的绘制帧数达到60帧。Android系统每隔16ms发出VSYNC信号,触发GPU对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。那一帧占用内存数呢?当画面的分辨率是1080×1920(目前最主流的分辨率),刷新率要达到60帧/秒时,那么显卡在一秒钟内需要处理的像素量就达到了“1080×1920×60=124416000”。那么一个“像素量”,相当与占用多少内存?我们用位图来代替粗略计算,把分辨率是1080×1920看成一张对应大小的位图,通过位图的大小来大概计算占用的内存大小。 1080×1920×16/8 = 4147200B = 4050KB = 3 MB,每秒钟需要处理3*60 = 180M的内存。这个数据量是相当大的了,所以滑动绘制过程必定采取了相应的策略增加绘制效率。
我们可以首先研究下ScrollView的滑动绘制原理,ScrollView相对于ListView等其他滑动控件功能更加单一,而且非常常用。说到滑动,必须先说明下View的绘制流程,这部分流程是相当的复杂的。分为以下几种情况1、开启了硬件加速 且滑动视图区域硬件加速关闭了但设置了软加速(缓存bitmap)2、开启硬件加速,滑动视图层硬件加速被关闭,软加速也没开启 3、开启了硬件加速 且滑动视图区域硬件加速也开启了。4、整体硬件加速没开启,但滑动视图区域软加速开启了 5、整体硬件加速没开启,软加速也没开启。听起来听绕口的,其实就是根据硬件加速分情况,View的层级上不能单独的开启硬件加速。所以列举出的情况是五种,而不是六种。关于硬件加速各层级开启方式如下:
在Android中,可以四给不同层次上开启硬件加速:
1、应用:
<application android:hardwareAccelerated="true">
2、Activity
<activity android:hardwareAccelerated="true">
3、Window
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
4、View
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
在这四个层次中,应用和Activity是可以选择的,Window只能打开,View只能关闭。
在apk的AndroidManifest中,如果指定了minSDKVersion&targetSDKVersion=7,会使得应用无法使用硬件加速进行绘图。
以上部分是从http://blog.csdn.net/oujunli/article/details/8570902 拷贝而来,如果不允许,请给我留言。
开启硬件加速View的绘制流程
1
2
3
4
5
6
7
8
9private void performDraw() { final boolean fullRedrawNeeded = mFullRedrawNeeded; mFullRedrawNeeded = false; try { draw(fullRedrawNeeded); } finally { } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31private void draw(boolean fullRedrawNeeded) { if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { // If accessibility focus moved, always invalidate the root. boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested; mInvalidateRootRequested = false; // Draw with hardware renderer. mIsAnimating = false; if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) { mHardwareYOffset = yOffset; mHardwareXOffset = xOffset; invalidateRoot = true; } if (invalidateRoot) { mAttachInfo.mHardwareRenderer.invalidateRoot(); } dirty.setEmpty(); // Stage the content drawn size now. It will be transferred to the renderer // shortly before the draw commands get send to the renderer. final boolean updated = updateContentDrawBounds(); if (mReportNextDraw) { // report next draw overrides setStopped() // This value is re-sync'd to the value of mStopped // in the handling of mReportNextDraw post-draw. mAttachInfo.mHardwareRenderer.setStopped(false); } if (updated) { requestDrawWindow(); } mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this); } }
1
2
3
4
5
6
7
8void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) { attachInfo.mIgnoreDirtyState = true; final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; choreographer.mFrameInfo.markDrawStart(); updateRootDisplayList(view, callbacks); attachInfo.mIgnoreDirtyState = false; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()"); updateViewTreeDisplayList(view); if (mRootNodeNeedsUpdate || !mRootNode.isValid()) { DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); try { final int saveCount = canvas.save(); canvas.translate(mInsetLeft, mInsetTop); callbacks.onHardwarePreDraw(canvas); canvas.insertReorderBarrier(); canvas.drawRenderNode(view.updateDisplayListIfDirty()); canvas.insertInorderBarrier(); callbacks.onHardwarePostDraw(canvas); canvas.restoreToCount(saveCount); mRootNodeNeedsUpdate = false; } finally { mRootNode.end(canvas); } } Trace.traceEnd(Trace.TRACE_TAG_VIEW); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45public RenderNode updateDisplayListIfDirty() { if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.isValid() || (mRecreateDisplayList)) { if (renderNode.isValid() && !mRecreateDisplayList) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList(); return renderNode; // no work needed } try { if (layerType == LAYER_TYPE_SOFTWARE) { buildDrawingCache(true); Bitmap cache = getDrawingCache(true); if (cache != null) { canvas.drawBitmap(cache, 0, 0, mLayerPaint); } } else { computeScroll(); canvas.translate(-mScrollX, -mScrollY); mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; // Fast path for layouts with no backgrounds if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); } } } finally { renderNode.end(canvas); setDisplayListProperties(renderNode); } } else { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; } return renderNode; }
未开启硬件加速View的绘制流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty) { Canvas canvas = mSurface.lockCanvas(dirty); mView.draw(canvas); return true; } mSurface.lockCanvas(dirty);会调用如下代码: public Canvas lockCanvas(Rect inOutDirty) throws Surface.OutOfResourcesException, IllegalArgumentException { Canvas mCanvas = new CompatibleCanvas(); return mCanvas; } }
ScrollView滑动流程分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // Treat animating scrolls differently; see #computeScroll() for why. if (!mScroller.isFinished()) { final int oldX = mScrollX; final int oldY = mScrollY; mScrollX = scrollX; mScrollY = scrollY; invalidateParentIfNeeded(); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (clampedY) { mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange()); } } else { super.scrollTo(scrollX, scrollY); } awakenScrollBars(); }
1
2
3
4
5
6
7
8
9postInvalidateOnAnimationScroll来更新视图。 public void postInvalidateOnAnimation() { // We try only with the AttachInfo because there's no point in invalidating // if we are not attached to our window final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); } }
最后
以上就是灵巧项链最近收集整理的关于Android 滑动绘制流程探究 系统是如何提高滑动性能?Android 滑动绘制流程探究 系统是如何提高滑动性能?的全部内容,更多相关Android内容请搜索靠谱客的其他文章。
发表评论 取消回复