【安卓深度控件开发(1.4)】Creating Custom Views (官方示例文档汉化版)(4)

假装没事ソ 提交于 2019-12-09 15:10:36

<h2>视图的优化</h2> <p>您现在有一个精心设计的视图,响应手势和平滑过渡,现在需要确保视图流畅。为了避免一个 UI 在播放过程中感觉缓慢或断断续续,您必须确保您的动画始终运行在每秒 60 帧。</p> <p>&#160;</p> <h3>少量的频繁处理</h3> <p>为了加快您的视图,在 <a href="http://developer.android.com/reference/android/view/View.html#onDraw(android.graphics.Canvas)" target="_blank">onDraw()</a> 中消除不必要的被频繁调用的例程代码,这将给你最大的回报。特别是在 <a href="http://developer.android.com/reference/android/view/View.html#onDraw(android.graphics.Canvas)" target="_blank">onDraw()</a> 中创建对象,因为这可能触发造成缓慢的垃圾回收。在初始化期间或动画之间分配对象。永远不要在动画运行时分配新对象。</p> <p>除了让 <a href="http://developer.android.com/reference/android/view/View.html#onDraw(android.graphics.Canvas)" target="_blank">onDraw()</a> 精简之外,您还应该确定尽可能的减少被调用。多数 <a href="http://developer.android.com/reference/android/view/View.html#onDraw(android.graphics.Canvas)" target="_blank">onDraw()</a> 调用由 <a href="http://developer.android.com/reference/android/view/View.html#invalidate()" target="_blank">invalidate()</a> 产生。所以应该排除不必要的 <a href="http://developer.android.com/reference/android/view/View.html#invalidate()" target="_blank">invalidate()</a> 调用。在可能的情况下,调用带有四个参数版本的 <a href="http://developer.android.com/reference/android/view/View.html#invalidate()" target="_blank">invalidate()</a> 而非无参数的版本。无参数的版本使整个视图无效,而四个参数的版本只会使视图的特定区域无效。此方法允许绘制要求可更有效并可以消除在无效矩形区域之外的区域。</p> <p>另一个非常低效的操作是遍历布局。当一个视图调用 <a href="http://developer.android.com/reference/android/view/View.html#requestLayout()" target="_blank">requestLayout()</a> , Android UI 系统必须遍历整个视图树来确定每个视图的大小。如果它发现有冲突的测量,它可能需要多次遍历层次结构。UI 设计师有时为了得到应有的行为创建深层嵌套的 <a href="http://developer.android.com/reference/android/view/ViewGroup.html" target="_blank">ViewGroup</a> 层次结构。这些深视图层次结构会导致性能问题。使您的视图层次结构尽可能浅。</p> <p>如果您有一个复杂的用户界面,您应考虑编写自定义 <a href="http://developer.android.com/reference/android/view/ViewGroup.html" target="_blank">ViewGroup</a>,以执行其布局。不像内建的视图,您的自定义视图可以做出特定于应用程序的子级大小和形状,假设,从而避免遍历其子级来计算测量。<font color="#006600">PieChart</font> 示例演示如何扩展视图分组作为自定义视图的一部分。<font color="#006600">PieChart</font> 有子视图,但它永远不会衡量他们。相反,它将根据自己的自定义布局算法直接设置其大小。</p> <p>&#160;</p> <h3>使用硬件加速</h3> <p>从 Android 3.0 开始, Android 2D 图形系统支持使用大多数新的 Android 设备上使用硬件 GPU(图形处理单元) 加速。对于很多应用程序来说, GPU 硬件加速可能导致巨大的性能提升,但它并不是每个应用程序的正确选择。Android 框架提供精细控制您的应用程序的哪些部分是或不是硬件加速的能力。</p> <p>查看 Android 开发手册中的<a href="http://developer.android.com/guide/topics/graphics/hardware-accel.html" target="_blank">硬件加速</a>了解如何在应用程序,活动或窗口级别启用硬件加速。请注意除了开发人员指南中的说明,您还必须通过在 <font color="#006600">AndroidManifest.xml</font> 中指定 <font color="#006600">&lt;uses-sdk android:targetSdkVersion=&quot;11&quot;/&gt;</font> 设置目标应用程序的 API 为 11 或更高。</p> <p>一旦您启用了硬件加速,你可能不会看到增加性能。移动 GPU 都非常擅长某些任务如缩放、 旋转以及处理位图图像。但可能不太擅长绘制线条与曲线这类的任务。要获得最大的 GPU 加速,您应该最大化 GPU 擅长的任务,减少它不擅长的任务。</p> <p>在 <font color="#006600">PieChart</font> 中,例如,绘制饼图是相对较慢的。每次旋转时重绘导致 UI 缓慢。解决方案是将饼图放置在一个子 <a href="http://developer.android.com/reference/android/view/View.html" target="_blank">View</a> 中并设置 <a href="http://developer.android.com/reference/android/view/View.html" target="_blank">View</a> 的<a href="http://developer.android.com/reference/android/view/View.html#setLayerType(int, android.graphics.Paint)" target="_blank">图层类型</a>为 <a href="http://developer.android.com/reference/android/view/View.html#LAYER_TYPE_HARDWARE">LAYER_TYPE_HARDWARE</a>。那么 GPU 可能将它缓存为静态图像。这个示例定义了一个 PieChart 的内部类,以最小化代码量更改来实现这一解决方案。</p> <div style="border-bottom: #ddd 1px solid; border-left: #ddd 1px solid; padding-bottom: 1em; margin: 0px 0px 1em; padding-left: 1em; padding-right: 1em; background: #f7f7f7; overflow: auto; border-top: #ddd 1px solid; border-right: #ddd 1px solid; padding-top: 1em"> <pre> <span style="color: #0000ff">private</span> <span style="color: #0000ff">class</span> PieView <span style="color: #0000ff">extends</span> View {

   <span style="color: #0000ff">public</span> PieView(Context context) {
       <span style="color: #0000ff">super</span>(context);
       <span style="color: #0000ff">if</span> (!isInEditMode()) {
           setLayerType(View.LAYER_TYPE_HARDWARE, <span style="color: #0000ff">null</span>);
       }
   }
   
   @Override
   <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> onDraw(Canvas canvas) {
       <span style="color: #0000ff">super</span>.onDraw(canvas);

       <span style="color: #0000ff">for</span> (Item it : mData) {
           mPiePaint.setShader(it.mShader);
           canvas.drawArc(mBounds,
                   360 - it.mEndAngle,
                   it.mEndAngle - it.mStartAngle,
                   <span style="color: #0000ff">true</span>, mPiePaint);
       }
   }

   @Override
   <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> onSizeChanged(<span style="color: #0000ff">int</span> w, <span style="color: #0000ff">int</span> h, <span style="color: #0000ff">int</span> oldw, <span style="color: #0000ff">int</span> oldh) {
       mBounds = <span style="color: #0000ff">new</span> RectF(0, 0, w, h);
   }

   RectF mBounds;

}</pre>

</div>

<br />

<p>完成这一更改后,<font color="#006600">PieChart.PieView.onDraw()</font> 方法只在第一次显示时调用。在其余的应用程序的生存期,饼图是作为图像缓存由 GPU 在不同旋转角度重绘。GPU 硬件是特别擅长这种事情,并立即产生明显的性能差异。</p>

<p>不过还有一种权衡。缓存图像作为硬件层消耗视频内存,这是一种有限的资源。基于这个原因,<font color="#006600">PieChart.PieView</font> 的最终版本只有当用户对其滚动时将图层类型设置为 <a href="http://developer.android.com/reference/android/view/View.html#LAYER_TYPE_NONE" target="_blank">LAYER_TYPE_HARDWARE</a> 。在其他情况下,它设置其图层类型为 LAYER_TYPE_NONE,它允许 GPU 停止缓存图像。</p>

<p>最后,不要忘记来分析您的代码。一个改善视图性能的技术可能在另一处使用时对性能造成负面影响。</p>

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!