diff options
Diffstat (limited to 'docs/html/training/custom-views/optimizing-view.jd')
| -rw-r--r-- | docs/html/training/custom-views/optimizing-view.jd | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/docs/html/training/custom-views/optimizing-view.jd b/docs/html/training/custom-views/optimizing-view.jd new file mode 100644 index 0000000..1f489dd --- /dev/null +++ b/docs/html/training/custom-views/optimizing-view.jd @@ -0,0 +1,176 @@ +page.title=Optimizing the View +parent.title=Creating Custom Views +parent.link=index.html + +trainingnavtop=true +previous.title=Making the View Interactive +previous.link=making-interactive.html + +@jd:body + +<div id="tb-wrapper"> + <div id="tb"> + + <h2>This lesson teaches you to</h2> + <ol> + <li><a href="#less">Do Less, Less Frequently</a></li> + <li><a href="#accelerate">Use Hardware Acceleration</a></li> + </ol> + + <h2>You should also read</h2> + <ul> + <li><a href=”{@docRoot}guide/topics/graphics/hardware-accel.html”> + Hardware Acceleration + </a> + </li> + </ul> +<h2>Try it out</h2> +<div class="download-box"> +<a href="{@docRoot}shareables/training/CustomView.zip" +class="button">Download the sample</a> +<p class="filename">CustomView.zip</p> +</div> +</div> + </div> + + +<p>Now that you have a well-designed view that responds to gestures and transitions between states, +you need to ensure +that the view runs fast. To avoid a UI that feels sluggish or stutters during playback, you must +ensure that your +animations consistently run at 60 frames per second.</p> + +<h2 id="less">Do Less, Less Frequently</h2> + +<p>To speed up your view, eliminate unnecessary code from routines that are called frequently. Start +by working on +{@link android.view.View#onDraw onDraw()}, which will give you the biggest payback. In particular +you should eliminate +allocations in {@link android.view.View#onDraw onDraw()}, because allocations may lead to a garbage +collection that +would cause a stutter. Allocate objects during initialization, or between animations. Never make an +allocation while an +animation is running.</p> + +<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, you should also make sure +it's called as +infrequently as possible. Most calls to {@link android.view.View#onDraw onDraw()} are the result of +a call to {@link +android.view.View#invalidate() invalidate()}, so eliminate unnecessary calls to {@link +android.view.View#invalidate() +invalidate()}. When possible, call the four-parameter variant of {@link +android.view.View#invalidate() invalidate()} +rather than the version that takes no parameters. The no-parameter variant invalidates the entire +view, while the +four-parameter variant invalidates only a specified portion of the view. This approach allows draw calls to +be more efficient and +can eliminate unnecessary invalidation of views that fall outside the invalid rectangle.</p> + +<p>Another very expensive operation is traversing layouts. Any time a view calls {@link +android.view.View#requestLayout() +requestLayout()}, the Android UI system needs to traverse the entire view hierarchy to find out how +big each view needs +to be. If it finds conflicting measurements, it may need to traverse the hierarchy multiple times. +UI designers +sometimes create deep hierarchies of nested {@link android.view.ViewGroup ViewGroup} objects in +order to get the UI to +behave properly. These deep view hierarchies cause performance problems. Make your view hierarchies +as shallow as +possible.</p> + +<p>If you have a complex UI, you should consider writing a custom {@link android.view.ViewGroup +ViewGroup} to perform +its layout. Unlike the built-in views, your custom view can make application-specific assumptions +about the size and +shape of its children, and thus avoid traversing its children to calculate measurements. The +PieChart example shows how +to extend {@link android.view.ViewGroup ViewGroup} as part of a custom view. PieChart has child +views, but it never +measures them. Instead, it sets their sizes directly according to its own custom layout +algorithm.</p> + +<h2 id="accelerate">Use Hardware Acceleration</h2> + +<p>As of Android 3.0, the Android 2D graphics system can be accelerated by the GPU (Graphics +Processing Unit) hardware +found in most newer Android devices. GPU hardware acceleration can result in a tremendous +performance increase for many +applications, but it isn't the right choice for every application. The Android framework +gives you the ability to finely control which parts of your application are or are not +hardware accelerated.</p> + +<p>See <a href="{@docRoot}guide/topics/graphics/hardware-accel.html">Hardware Acceleration</a> + in the Android Developers Guide for directions on how to enable acceleration at the + application, activity, or window level. Notice that in addition to the directions in + the developer guide, you must also set your application's target API to 11 or higher by + specifying {@code <uses-sdk + android:targetSdkVersion="11"/>} in your {@code AndroidManifest.xml} file.</p> + +<p>Once you've enabled hardware acceleration, you may or may not see a performance increase. +Mobile GPUs are very good at certain tasks, such as scaling, rotating, and translating +bitmapped images. They are not particularly good at other tasks, such as drawing lines or curves. To +get the most out of GPU acceleration, you should maximize the number of operations that the GPU is +good at, and minimize the number of operations that the GPU isn't good at.</p> + +<p>In the PieChart example, for instance, drawing the pie is relatively expensive. Redrawing the pie +each time it's +rotated causes the UI to feel sluggish. The solution is to place the pie chart into a child +{@link android.view.View} and set that +{@link android.view.View}'s +<a href="{@docRoot}reference/android/view/View.html#setLayerType(int, android.graphics.Paint)"> + layer type</a> to {@link android.view.View#LAYER_TYPE_HARDWARE}, so that the GPU can cache it as +a static +image. The sample +defines the child view as an inner class of {@code PieChart}, which minimizes the amount of code +changes that are needed +to implement this solution.</p> + +<pre> + private class PieView extends View { + + public PieView(Context context) { + super(context); + if (!isInEditMode()) { + setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + for (Item it : mData) { + mPiePaint.setShader(it.mShader); + canvas.drawArc(mBounds, + 360 - it.mEndAngle, + it.mEndAngle - it.mStartAngle, + true, mPiePaint); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mBounds = new RectF(0, 0, w, h); + } + + RectF mBounds; + } +</pre> + +<p>After this code change, {@code PieChart.PieView.onDraw()} is called only when the view is first +shown. During the rest +of the application's lifetime, the pie chart is cached as an image, and redrawn at different +rotation angles by the GPU. +GPU hardware is particularly good at this sort of thing, and the performance difference is +immediately noticeable.</p> + +<p>There is a tradeoff, though. Caching images as hardware layers consumes video memory, which is a +limited resource. +For this reason, the final version of {@code PieChart.PieView} only sets its layer type to +{@link android.view.View#LAYER_TYPE_HARDWARE} +while the user is actively scrolling. At all other times, it sets its layer type to +{@link android.view.View#LAYER_TYPE_NONE}, which +allows the GPU to stop caching the image.</p> + +<p>Finally, don't forget to profile your code. Techniques that improve performance on one view +might negatively affect performance on another.</p> |
