682 lines
29 KiB
Plaintext
682 lines
29 KiB
Plaintext
page.title=Hardware Acceleration
|
||
parent.title=Graphics
|
||
parent.link=index.html
|
||
@jd:body
|
||
|
||
|
||
<div id="qv-wrapper">
|
||
<div id="qv">
|
||
<h2>In this document</h2>
|
||
|
||
<ol>
|
||
<li><a href="#controlling">Controlling Hardware Acceleration</a></li>
|
||
<li><a href="#determining">Determining if a View is Hardware Accelerated</a></li>
|
||
<li><a href="#model">Android Drawing Models</a>
|
||
|
||
<ol>
|
||
<li><a href="#software-model">Software-based drawing model</a></li>
|
||
<li><a href="#hardware-model">Hardware accelerated drawing model</a></li>
|
||
</ol>
|
||
</li>
|
||
|
||
<li>
|
||
<a href="#unsupported">Unsupported Drawing Operations</a>
|
||
</li>
|
||
|
||
|
||
|
||
<li>
|
||
<a href="#layers">View Layers</a>
|
||
|
||
<ol>
|
||
<li><a href="#layers-anims">View Layers and Animations</a></li>
|
||
</ol>
|
||
</li>
|
||
|
||
<li><a href="#tips">Tips and Tricks</a></li>
|
||
</ol>
|
||
|
||
<h2>See also</h2>
|
||
|
||
<ol>
|
||
<li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL with the Framework
|
||
APIs</a></li>
|
||
|
||
<li><a href="{@docRoot}guide/topics/renderscript/index.html">Renderscript</a></li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
|
||
<p>Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline supports hardware
|
||
acceleration, meaning that all drawing operations that are performed on a {@link
|
||
android.view.View}'s canvas use the GPU. Because of the increased resources required to enable
|
||
hardware acceleration, your app will consume more RAM.</p>
|
||
|
||
<p>Hardware acceleration is enabled by default if your Target API level is >=14, but can also
|
||
be explicitly enabled. If your application uses only standard views and {@link
|
||
android.graphics.drawable.Drawable}s, turning it on globally should not cause any adverse drawing
|
||
effects. However, because hardware acceleration is not supported for all of the 2D drawing
|
||
operations, turning it on might affect some of your custom views or drawing calls. Problems
|
||
usually manifest themselves as invisible elements, exceptions, or wrongly rendered pixels. To
|
||
remedy this, Android gives you the option to enable or disable hardware acceleration at multiple
|
||
levels. See <a href="#controlling">Controlling Hardware Acceleration</a>.</p>
|
||
|
||
<p>If your application performs custom drawing, test your application on actual hardware devices
|
||
with hardware acceleration turned on to find any problems. The <a
|
||
href="#drawing-support">Unsupported drawing operations</a> section describes known issues with
|
||
hardware acceleration and how to work around them.</p>
|
||
|
||
<h2 id="controlling">Controlling Hardware Acceleration</h2>
|
||
<p>You can control hardware acceleration at the following levels:</p>
|
||
<ul>
|
||
<li>Application</li>
|
||
|
||
<li>Activity</li>
|
||
|
||
<li>Window</li>
|
||
|
||
<li>View</li>
|
||
</ul>
|
||
|
||
<h4>Application level</h4>
|
||
<p>In your Android manifest file, add the following attribute to the
|
||
<a href="{@docRoot}guide/topics/manifest/application-element.html">
|
||
<code><application></code></a> tag to enable hardware acceleration for your entire
|
||
application:</p>
|
||
|
||
<pre>
|
||
<application android:hardwareAccelerated="true" ...>
|
||
</pre>
|
||
|
||
<h4>Activity level</h4>
|
||
<p>If your application does not behave properly with hardware acceleration turned on globally, you
|
||
can control it for individual activities as well. To enable or disable hardware acceleration at
|
||
the activity level, you can use the <code>android:hardwareAccelerated</code> attribute for
|
||
the <a href="{@docRoot}guide/topics/manifest/activity-element.html">
|
||
<code><activity></code></a> element. The following example enables hardware acceleration for
|
||
the entire application but disables it for one activity:</p>
|
||
|
||
<pre>
|
||
<application android:hardwareAccelerated="true">
|
||
<activity ... />
|
||
<activity android:hardwareAccelerated="false" />
|
||
</application>
|
||
</pre>
|
||
|
||
<h4>Window level</h4>
|
||
<p>If you need even more fine-grained control, you can enable hardware acceleration for a given
|
||
window with the following code:</p>
|
||
|
||
<pre>
|
||
getWindow().setFlags(
|
||
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
|
||
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
|
||
|
||
</pre>
|
||
|
||
<p class="note"><strong>Note</strong>: You currently cannot disable hardware acceleration at
|
||
the window level.</p>
|
||
|
||
<h4>View level</h4>
|
||
|
||
<p>You can disable hardware acceleration for an individual view at runtime with the
|
||
following code:</p>
|
||
|
||
<pre>
|
||
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||
</pre>
|
||
|
||
<p class="note"><strong>Note</strong>: You currently cannot enable hardware acceleration at
|
||
the view level. View layers have other functions besides disabling hardware acceleration. See <a
|
||
href="#layers">View layers</a> for more information about their uses.</p>
|
||
|
||
<h2 id="determining">Determining if a View is Hardware Accelerated</h2>
|
||
|
||
<p>It is sometimes useful for an application to know whether it is currently hardware
|
||
accelerated, especially for things such as custom views. This is particularly useful if your
|
||
application does a lot of custom drawing and not all operations are properly supported by the new
|
||
rendering pipeline.</p>
|
||
|
||
<p>There are two different ways to check whether the application is hardware accelerated:</p>
|
||
|
||
<ul>
|
||
<li>{@link android.view.View#isHardwareAccelerated View.isHardwareAccelerated()} returns
|
||
<code>true</code> if the {@link android.view.View} is attached to a hardware accelerated
|
||
window.</li>
|
||
|
||
<li>{@link android.graphics.Canvas#isHardwareAccelerated Canvas.isHardwareAccelerated()}
|
||
returns <code>true</code> if the {@link android.graphics.Canvas} is hardware accelerated</li>
|
||
</ul>
|
||
|
||
<p>If you must do this check in your drawing code, use {@link
|
||
android.graphics.Canvas#isHardwareAccelerated Canvas.isHardwareAccelerated()} instead of {@link
|
||
android.view.View#isHardwareAccelerated View.isHardwareAccelerated()} when possible. When a view
|
||
is attached to a hardware accelerated window, it can still be drawn using a non-hardware
|
||
accelerated Canvas. This happens, for instance, when drawing a view into a bitmap for caching
|
||
purposes.</p>
|
||
|
||
|
||
<h2 id="model">Android Drawing Models</h2>
|
||
|
||
<p>When hardware acceleration is enabled, the Android framework utilizes a new drawing model that
|
||
utilizes <em>display lists</em> to render your application to the screen. To fully understand
|
||
display lists and how they might affect your application, it is useful to understand how Android
|
||
draws views without hardware acceleration as well. The following sections describe the
|
||
software-based and hardware-accelerated drawing models.</p>
|
||
|
||
<h3 id="software-model">Software-based drawing model</h3>
|
||
<p>In the software drawing model, views are drawn with the following two steps:</p>
|
||
<ol>
|
||
<li>Invalidate the hierarchy</li>
|
||
|
||
<li>Draw the hierarchy</li>
|
||
</ol>
|
||
|
||
<p>Whenever an application needs to update a part of its UI, it invokes {@link
|
||
android.view.View#invalidate invalidate()} (or one of its variants) on any view that has changed
|
||
content. The invalidation messages are propagated all the way up the view hierarchy to compute
|
||
the regions of the screen that need to be redrawn (the dirty region). The Android system then
|
||
draws any view in the hierarchy that intersects with the dirty region. Unfortunately, there are
|
||
two drawbacks to this drawing model:</p>
|
||
<ul>
|
||
<li>First, this model requires execution of a lot of code on every draw pass. For example, if
|
||
your application calls {@link android.view.View#invalidate invalidate()} on a button and that
|
||
button sits on top of another view, the Android system redraws the view even though it hasn't
|
||
changed.</li>
|
||
<li>The second issue is that the drawing model can hide bugs in your application. Since the
|
||
Android system redraws views when they intersect the dirty region, a view whose content you
|
||
changed might be redrawn even though {@link android.view.View#invalidate invalidate()} was not
|
||
called on it. When this happens, you are relying on another view being invalidated to obtain the
|
||
proper behavior. This behavior can change every time you modify your application. Because of
|
||
this, you should always call {@link android.view.View#invalidate invalidate()} on your custom
|
||
views whenever you modify data or state that affects the view’s drawing code.</li>
|
||
</ul>
|
||
|
||
<p class="note"><strong>Note</strong>: Android views automatically call {@link
|
||
android.view.View#invalidate invalidate()} when their properties change, such as the background
|
||
color or the text in a {@link android.widget.TextView}.</p>
|
||
|
||
<h3 id="hardware-model">Hardware accelerated drawing model</h3>
|
||
<p>The Android system still uses {@link android.view.View#invalidate invalidate()} and {@link
|
||
android.view.View#draw draw()} to request screen updates and to render views, but handles the
|
||
actual drawing differently. Instead of executing the drawing commands immediately, the Android
|
||
system records them inside display lists, which contain the output of the view hierarchy’s
|
||
drawing code. Another optimization is that the Android system only needs to record and update
|
||
display lists for views marked dirty by an {@link android.view.View#invalidate invalidate()}
|
||
call. Views that have not been invalidated can be redrawn simply by re-issuing the previously
|
||
recorded display list. The new drawing model contains three stages:</p>
|
||
|
||
<ol>
|
||
<li>Invalidate the hierarchy</li>
|
||
|
||
<li>Record and update display lists</li>
|
||
|
||
<li>Draw the display lists</li>
|
||
</ol>
|
||
|
||
<p>With this model, you cannot rely on a view intersecting the dirty region to have its {@link
|
||
android.view.View#draw draw()} method executed. To ensure that the Android system records a
|
||
view’s display list, you must call {@link android.view.View#invalidate invalidate()}. Forgetting
|
||
to do so causes a view to look the same even after it has been changed.</p>
|
||
|
||
<p>Using display lists also benefits animation performance because setting specific properties,
|
||
such as alpha or rotation, does not require invalidating the targeted view (it is done
|
||
automatically). This optimization also applies to views with display lists (any view when your
|
||
application is hardware accelerated.) For example, assume there is a {@link
|
||
android.widget.LinearLayout} that contains a {@link android.widget.ListView} above a {@link
|
||
android.widget.Button}. The display list for the {@link android.widget.LinearLayout} looks like
|
||
this:</p>
|
||
|
||
<ul>
|
||
<li>DrawDisplayList(ListView)</li>
|
||
|
||
<li>DrawDisplayList(Button)</li>
|
||
</ul>
|
||
|
||
<p>Assume now that you want to change the {@link android.widget.ListView}'s opacity. After
|
||
invoking <code>setAlpha(0.5f)</code> on the {@link android.widget.ListView}, the display list now
|
||
contains this:</p>
|
||
|
||
<ul>
|
||
<li>SaveLayerAlpha(0.5)</li>
|
||
|
||
<li>DrawDisplayList(ListView)</li>
|
||
|
||
<li>Restore</li>
|
||
|
||
<li>DrawDisplayList(Button)</li>
|
||
</ul>
|
||
|
||
<p>The complex drawing code of {@link android.widget.ListView} was not executed. Instead, the
|
||
system only updated the display list of the much simpler {@link android.widget.LinearLayout}. In
|
||
an application without hardware acceleration enabled, the drawing code of both the list and its
|
||
parent are executed again.</p>
|
||
|
||
<h2 id="unsupported">Unsupported Drawing Operations</h2>
|
||
|
||
<p>When hardware accelerated, the 2D rendering pipeline supports the most commonly used {@link
|
||
android.graphics.Canvas} drawing operations as well as many less-used operations. All of the
|
||
drawing operations that are used to render applications that ship with Android, default widgets
|
||
and layouts, and common advanced visual effects such as reflections and tiled textures are
|
||
supported.</p>
|
||
|
||
<p>The following table describes the support level of various operations across API levels:</p>
|
||
|
||
<style type="text/css">
|
||
.tblGenFixed, .tblGeneric{font-size:15px}.tblGenFixed td {padding:0 3px;letter-spacing:0;word-spacing:0;background-color:#fff;z-index:1;border-top:0px none;border-left:0px none;border-bottom:1px solid #CCC;border-right:1px solid #CCC;} .dn {display:none} .tblGenFixed td.s0 {background-color:white;border-top:1px solid #CCC;border-left:1px solid #CCC;} .tblGenFixed td.s1 {background-color:#434343;color:#ffffff;text-align:center;border-top:1px solid #CCC;} .tblGenFixed td.s3 {background-color:white;color:#000000;text-align:center;} .tblGenFixed td.s5 {background-color:#434343;color:#ffffff;text-align:left;border-left:1px solid #CCC;} .tblGenFixed td.label_pos {background-color:white;font-family:courier new,monospace;color:#000000;text-align:right;border-left:1px solid #CCC;} .tblGenFixed td.label_neg {background-color:#ececec;font-family:courier new,monospace;color:#000000;text-align:right;border-left:1px solid #CCC;} .tblGenFixed td.value_pos {background-color:white;color:#000000;text-align:center;} .tblGenFixed td.value_neg {background-color:#ececec;color:#980000;text-align:center;}
|
||
</style>
|
||
<table border="0" cellpadding="0" cellspacing="0" class="tblGenFixed" id="tblMain">
|
||
<tbody>
|
||
<tr class="rShim">
|
||
<td class="rShim" style="width:380px;"></td>
|
||
<td class="rShim" style="width:240px;"></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="s0"></td>
|
||
<td class="s1">First supported API level</td>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="5" class="s5">Canvas</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">drawBitmapMesh() (colors array)</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">drawPicture()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">drawPosText()</td>
|
||
<td class="value_pos">16</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">drawTextOnPath()</td>
|
||
<td class="value_pos">16</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">drawVertices()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setDrawFilter()</td>
|
||
<td class="value_pos">16</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">clipPath()</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">clipRegion()</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">clipRect(Region.Op.XOR)</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">clipRect(Region.Op.Difference)</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">clipRect(Region.Op.ReverseDifference)</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">clipRect() with rotation/perspective</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">drawArc()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">drawRoundRect()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">saveLayer() with RectF dimensions</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">saveLayer() with float dimensions</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">saveLayerAlpha() with RectF dimensions</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">saveLayerAlpha() with float dimensions</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="5" class="s5">Paint</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setAntiAlias() (for text)</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setAntiAlias() (for lines)</td>
|
||
<td class="value_pos">16</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setFilterBitmap()</td>
|
||
<td class="value_pos">17</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">setLinearText()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">setMaskFilter()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">setPathEffect() (for lines)</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">setRasterizer()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">setShadowLayer() (other than text)</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setStrokeCap() (for lines)</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setStrokeCap() (for points)</td>
|
||
<td class="value_pos">19</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">setSubpixelText()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">getFontFeatureSettings()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">isElegantTextHeight()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">isElegantTextHeight()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setFontFeatureSettings()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">setLetterSpacing()</td>
|
||
<td class="value_pos">21</td>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="5" class="s5">Xfermode</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">AvoidXfermode</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">PixelXorXfermode</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">PorterDuff.Mode.DARKEN (framebuffer)</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">PorterDuff.Mode.LIGHTEN (framebuffer)</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">PorterDuff.Mode.OVERLAY (framebuffer)</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="5" class="s5">Shader</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">ComposeShader inside ComposeShader</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">Same type shaders inside ComposeShader</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">Local matrix on ComposeShader</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 id="scaling">Canvas Scaling</h3>
|
||
|
||
<p>The hardware accelerated 2D rendering pipeline was built first to support unscaled drawing,
|
||
with some drawing operations degrading quality significantly at higher scale values. These
|
||
operations are implemented as textures drawn at scale 1.0, transformed by the GPU. In API level
|
||
<17, using these operations will result in scaling artifacts increasing with scale.</p>
|
||
|
||
The following table shows when implementation was changed to correctly handle large scales:
|
||
|
||
<table border="0" cellpadding="0" cellspacing="0" class="tblGenFixed" id="tblMain">
|
||
<tbody>
|
||
<tr class="rShim">
|
||
<td class="rShim" style="width:380px;"></td>
|
||
<td class="rShim" style="width:240px;"></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="s5">Drawing operation to be scaled</td>
|
||
<td class="s1">First supported API level</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">drawText()</td>
|
||
<td class="value_pos">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">drawPosText()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">drawTextOnPath()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_pos">Simple Shapes*</td>
|
||
<td class="value_pos">17</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">Complex Shapes*</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">drawPath()</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="label_neg">Shadow layer</td>
|
||
<td class="value_neg">✗</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p class="note"><strong>Note</strong>: 'Simple' shapes are <code>drawRect()</code>,
|
||
<code>drawCircle()</code>, <code>drawOval()</code>, <code>drawRoundRect()</code>, and
|
||
<code>drawArc()</code> (with useCenter=false) commands issued with a Paint that doesn't have a
|
||
PathEffect, and doesn't contain non-default joins (via <code>setStrokeJoin()</code> /
|
||
<code>setStrokeMiter()</code>). Other instances of those draw commands fall under 'Complex,' in
|
||
the above chart.</p>
|
||
|
||
<p>If your application is affected by any of these missing features or limitations, you can turn
|
||
off hardware acceleration for just the affected portion of your application by calling {@link
|
||
android.view.View#setLayerType setLayerType(View.LAYER_TYPE_SOFTWARE, null)}. This way, you can
|
||
still take advantage of hardware acceleration everywhere else. See <a
|
||
href="#controlling">Controlling Hardware Acceleration</a> for more information on how to enable
|
||
and disable hardware acceleration at different levels in your application.
|
||
|
||
<h2 id="layers">View Layers</h2>
|
||
|
||
<p>In all versions of Android, views have had the ability to render into off-screen buffers,
|
||
either by using a view's drawing cache, or by using {@link android.graphics.Canvas#saveLayer
|
||
Canvas.saveLayer()}. Off-screen buffers, or layers, have several uses. You can use them to get
|
||
better performance when animating complex views or to apply composition effects. For instance,
|
||
you can implement fade effects using <code>Canvas.saveLayer()</code> to temporarily render a view
|
||
into a layer and then composite it back on screen with an opacity factor.</p>
|
||
|
||
<p>Beginning in Android 3.0 (API level 11), you have more control on how and when to use layers
|
||
with the {@link android.view.View#setLayerType View.setLayerType()} method. This API takes two
|
||
parameters: the type of layer you want to use and an optional {@link android.graphics.Paint}
|
||
object that describes how the layer should be composited. You can use the {@link
|
||
android.graphics.Paint} parameter to apply color filters, special blending modes, or opacity to a
|
||
layer. A view can use one of three layer types:</p>
|
||
|
||
<ul>
|
||
<li>{@link android.view.View#LAYER_TYPE_NONE}: The view is rendered normally and is not backed
|
||
by an off-screen buffer. This is the default behavior.</li>
|
||
|
||
<li>{@link android.view.View#LAYER_TYPE_HARDWARE}: The view is rendered in hardware into a
|
||
hardware texture if the application is hardware accelerated. If the application is not hardware
|
||
accelerated, this layer type behaves the same as {@link
|
||
android.view.View#LAYER_TYPE_SOFTWARE}.</li>
|
||
|
||
<li>{@link android.view.View#LAYER_TYPE_SOFTWARE}: The view is rendered in software into a
|
||
bitmap.</li>
|
||
</ul>
|
||
|
||
<p>The type of layer you use depends on your goal:</p>
|
||
|
||
<ul>
|
||
<li><strong>Performance</strong>: Use a hardware layer type to render a view into a hardware
|
||
texture. Once a view is rendered into a layer, its drawing code does not have to be executed
|
||
until the view calls {@link android.view.View#invalidate invalidate()}. Some animations, such as
|
||
alpha animations, can then be applied directly onto the layer, which is very efficient
|
||
for the GPU to do.</li>
|
||
|
||
<li><strong>Visual effects</strong>: Use a hardware or software layer type and a {@link
|
||
android.graphics.Paint} to apply special visual treatments to a view. For instance, you can
|
||
draw a view in black and white using a {@link
|
||
android.graphics.ColorMatrixColorFilter}.</li>
|
||
|
||
<li><strong>Compatibility</strong>: Use a software layer type to force a view to be rendered in
|
||
software. If a view that is hardware accelerated (for instance, if your whole
|
||
application is hardware acclerated), is having rendering problems, this is an easy way to work
|
||
around limitations of the hardware rendering
|
||
pipeline.</li>
|
||
</ul>
|
||
|
||
<h3 id="layers-anims">View layers and animations</h3>
|
||
|
||
<p>Hardware layers can deliver faster and smoother animations when your application
|
||
is hardware accelerated. Running an animation at 60 frames per second is not always possible when
|
||
animating complex views that issue a lot of drawing operations. This can be alleviated by
|
||
using hardware layers to render the view to a hardware texture. The hardware texture can
|
||
then be used to animate the view, eliminating the need for the view to constantly redraw itself
|
||
when it is being animated. The view is not redrawn unless you change the view's
|
||
properties, which calls {@link android.view.View#invalidate invalidate()}, or if you call {@link
|
||
android.view.View#invalidate invalidate()} manually. If you are running an animation in
|
||
your application and do not obtain the smooth results you want, consider enabling hardware layers on
|
||
your animated views.</p>
|
||
|
||
<p>When a view is backed by a hardware layer, some of its properties are handled by the way the
|
||
layer is composited on screen. Setting these properties will be efficient because they do not
|
||
require the view to be invalidated and redrawn. The following list of properties affect the way
|
||
the layer is composited. Calling the setter for any of these properties results in optimal
|
||
invalidation and no redrawing of the targeted view:</p>
|
||
|
||
<ul>
|
||
<li><code>alpha</code>: Changes the layer's opacity</li>
|
||
|
||
<li><code>x</code>, <code>y</code>, <code>translationX</code>, <code>translationY</code>:
|
||
Changes the layer's position</li>
|
||
|
||
<li><code>scaleX</code>, <code>scaleY</code>: Changes the layer's size</li>
|
||
|
||
<li><code>rotation</code>, <code>rotationX</code>, <code>rotationY</code>: Changes the
|
||
layer's orientation in 3D space</li>
|
||
|
||
<li><code>pivotX</code>, <code>pivotY</code>: Changes the layer's transformations origin</li>
|
||
</ul>
|
||
|
||
<p>These properties are the names used when animating a view with an {@link
|
||
android.animation.ObjectAnimator}. If you want to access these properties, call the appropriate
|
||
setter or getter. For instance, to modify the alpha property, call {@link
|
||
android.view.View#setAlpha setAlpha()}. The following code snippet shows the most efficient way
|
||
to rotate a viewiew in 3D around the Y-axis:</p>
|
||
<pre>
|
||
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||
ObjectAnimator.ofFloat(view, "rotationY", 180).start();
|
||
</pre>
|
||
|
||
<p>Because hardware layers consume video memory, it is highly recommended that you enable them
|
||
only for the duration of the animation and then disable them after the animation is done. You
|
||
can accomplish this using animation listeners:</p>
|
||
<pre>
|
||
View.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
|
||
animator.addListener(new AnimatorListenerAdapter() {
|
||
@Override
|
||
public void onAnimationEnd(Animator animation) {
|
||
view.setLayerType(View.LAYER_TYPE_NONE, null);
|
||
}
|
||
});
|
||
animator.start();
|
||
</pre>
|
||
|
||
<p>For more information on property animation, see <a href=
|
||
"{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a>.</p>
|
||
|
||
<h2 id="tips">Tips and Tricks</h2>
|
||
|
||
<p>Switching to hardware accelerated 2D graphics can instantly increase performance, but you
|
||
should still design your application to use the GPU effectively by following these
|
||
recommendations:</p>
|
||
|
||
<dl>
|
||
<dt><strong>Reduce the number of views in your application</strong></dt>
|
||
|
||
<dd>The more views the system has to draw, the slower it will be. This applies to the software
|
||
rendering pipeline as well. Reducing views is one of the easiest ways to optimize your UI.</dd>
|
||
|
||
<dt><strong>Avoid overdraw</strong></dt>
|
||
|
||
<dd>Do not draw too many layers on top of each other. Remove any views that are completely
|
||
obscured by other opaque views on top of it. If you need to draw several layers blended on top
|
||
of each other, consider merging them into a single layer. A good rule of thumb with current
|
||
hardware is to not draw more than 2.5 times the number of pixels on screen per frame
|
||
(transparent pixels in a bitmap count!).</dd>
|
||
|
||
<dt><strong>Don't create render objects in draw methods</strong></dt>
|
||
|
||
<dd>A common mistake is to create a new {@link android.graphics.Paint} or a new {@link
|
||
android.graphics.Path} every time a rendering method is invoked. This forces the garbage
|
||
collector to run more often and also bypasses caches and optimizations in the hardware
|
||
pipeline.</dd>
|
||
|
||
<dt><strong>Don't modify shapes too often</strong></dt>
|
||
|
||
<dd>Complex shapes, paths, and circles for instance, are rendered using texture masks. Every
|
||
time you create or modify a path, the hardware pipeline creates a new mask, which can be
|
||
expensive.</dd>
|
||
|
||
<dt><strong>Don't modify bitmaps too often</strong></dt>
|
||
|
||
<dd>Every time you change the content of a bitmap, it is uploaded again as a GPU texture the
|
||
next time you draw it.</dd>
|
||
|
||
<dt><strong>Use alpha with care</strong></dt>
|
||
|
||
<dd>When you make a view translucent using {@link android.view.View#setAlpha setAlpha()},
|
||
{@link android.view.animation.AlphaAnimation}, or {@link android.animation.ObjectAnimator}, it
|
||
is rendered in an off-screen buffer which doubles the required fill-rate. When applying alpha
|
||
on very large views, consider setting the view's layer type to
|
||
<code>LAYER_TYPE_HARDWARE</code>.</dd>
|
||
</dl>
|