In the Android development process is faced with an application to make, and then make it a good application process, one of the most intuitive is the application of the UI smoothness.
Here is a summary of some of the performance-related knowledge ~
first, the reasons for the UI lag
First, we often encounter these statements when we evaluate the UI:
1. "This animation is less than 30 frames, Kacheng dog"
2. "This frame rate is obviously more than 50, how is the feeling of Kaka"
3. "I'm shaking when I'm dragging."
There are actually two problems here:
A1. Low average frame rate
A2. Average frame rate up, but drop frame
The frame rate is not good enough to understand, the scene of the drop frame is probably like this
Each column of color block represents the drawing time of a frame, the longer the color block is wider, then you can find that the following column frame rate of 40 of the animation in the middle of a paragraph leaked a frame (perhaps this time the CPU blocked the empty drawing), in the back there is a very long drawing (may be drawing a very time-consuming thing). Then the overall performance is the following animation in the playback process will obviously card two times, performance is not as good as the above FPS30 animation.
Summary:
Therefore, when evaluating the animation, it will be found that high frame rate is the necessary condition for animation fluency,
But it's not a sufficient condition,
The average frame rate determines the upper limit of the animation experience,
But the sense of Dayton is often the lowest frame rate , and a 80ms lag will ruin the animation you seem to have reached 60FPS.
Ps. Other reasons for Dayton
In addition to these two main, there are also some individuals encounter small details will also have an impact:
- Animation first frame response is not timely caused by the animation "do not stick to the hand" feeling
- Use an unreasonable animation curve/interpolator
second, how to view the performance of the current animation
Think the animation comparison card This thing is too subjective, we need to have something intuitive to support the confirmation.
The usual phone screen refresh rate is 60Hz, so that determines that our animation is the upper limit of 60FPS, and then high is not very significant.
Then draw 60 frames per second, the time per frame is 1000/60 = ms
Now look at this.
Tool 1:gfxinfo
This can be used to view the time spent on the most recently drawn frames, and more than 4.1 of the machines can be viewed directly in the developer options-GPU rendering mode analysis. 4.1 of the following can only be pulled through the ADB data.
With this intuitive view, we can quickly discover some of the problems:
This green line represents 16ms, and the histogram height over green lines indicates that the frame draws more time than the standard.
The bar chart is divided into three parts,
Blue "Update displaylist"
Red "Process displaylist"
Yellow "Swap Buffers"
If there is one or more bar chart more than the standard, then this animation can have a relatively large performance problem (the application in the figure is more than, but not much, so the impact is not very large)
Another of course is in the code directly, calculate the number of OnDraw in the animation process of the view, and then calculate the frame rate, this is a more intuitive measure.
Iii. implementing targeted programs for different types of lag
1. Enable Hardware acceleration
Android starts with 3.0 (API level 11) and supports hardware acceleration when drawing the view.
Take advantage of the features of the GPU, making the drawing smoother, but consuming a bit more memory.
2. Reduce the average single frame drawing time, optimize the drawing scheme
For the A1 of the average frame rate mentioned in our case, most of the single frame draw time is too long, such as the UI layout is too complex, the tree structure is too deep.
Here are some recommended ways to optimize:
2.1 Reducing the View tree level
Tool 2:hierarchyviewer
The tool can only be used on viewserver machines, and ordinary commercial phones will not connect. Just like Google's official machine, some engineering machines (previously seen by a millet engineering machine) can be identified. By some means can also give the ordinary mobile phone to open viewserver, but I tried to fail.
The tool can be very intuitive to see the tree structure of the UI, where the stack of too many meaningless layers is basically at a glance, you will find that the app always inadvertently nested a framelayout more, You can use TextView's leftdrawable when you want to use it as a combination of LinearLayout + ImageView + TextView. In short, our goal is to make the view tree flattened, with no deep structure.
There are some articles advocating the use of relativelayout in complex scenarios to layout, the personal perception of the disadvantage is that the UI code becomes more difficult to read, need to constantly see the layout of the relationship between the various views. So it is recommended only when the real need to optimize the time to proceed, pre-development or easy to use.
2.2 Decrease Overdraw (repeat draw)
Just pick up your app, open developer mode-debug GPU transition drawing, go back to your app, and take a good look at where the rendering will be repeatedly drawn.
A good app should not have too many red areas to appear.
To do: Pending pits
2.3 Avoid handling too many things on critical paths
This kind of thing often appears in the code we inadvertently write:
@OverrideprotectedvoidonDraw(Canvas canvas) { new Paint(); paint.setTextSize(15); canvas.drawText("重复创建paint对象"00, paint);}
It is necessary to avoid the time-consuming operations such as creating new objects, IO processing, etc. on frequently called paths such as Measure/layout/draw/getview. The frequent creation of objects, in addition to the time-consuming of frequent executions, also results in large amounts of memory fragmentation that can cause unnecessary trouble when the GC is triggered at some point.
Although we all understand the truth, there will always be some casual time stepping into these pits in real demand.
e.g. a ListView in GetView need to pick up some of the data,getview to be used to display after layer requests, over the controller, finally in the model to access the database, so the list of sliding becomes very pit dad.
Solution 1: Add a memory cache, buffer part of the data, reduce IO operations.
2.3 Sometimes drawing bitmap is quicker than drawing a bunch of complicated stuff.
We know that a viiew to show the need to go through the measure-layout-draw process, then a more complex structure of the viewgroup in this process will take a long time, resulting in longer drawing; A custom view if you draw a lot of text during draw (the text is much more time consuming than the basic graphics and textures), there is also a performance problem with drawing.
This time, if can take a bitmap directly affixed to, reduce the time of measurelayout or render the text, that will greatly improve the efficiency (see the following pre-drawing in detail)
2.4 Draw bitmap by sacrificing color to exchange speed (and reduce memory)
When creating a bitmap, you can select a variety of properties:
Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);RGB_565 //表示分别用5位,6位,5位来记录红,绿,蓝的颜色值,没有透明度 //一个像素所占内存 5+6+5 = 16bit = 2BytesARGB_4444 //表示各用4位来记录红,绿,蓝和透明度ARGB_8888 //表示各用8位来记录红,绿,蓝和透明度
Visible argb_8888 is the best display, can show 2^16 color, but the corresponding disadvantage is that the memory will be larger than the previous two times, larger memory in addition to the meaning of memory explosion table, the performance of the drawing will have a great impact.
Therefore, we advocate, in the use of large image animation (screen size), as far as possible in the display effect compromise, using rgb_565 (non-transparent) and argb_4444 (transparent) for the decode of the picture, the animation frame rate will be significantly improved.
2.5 Pre-prepared content for animation
There are two kinds of
1. Pre-loading resources/data
2. Pre-Drawing
To do: Pending pits
2.6 Transparent maps, colors, etc. will consume more drawing performance
We often get the designer's sister. UI annotations are like this:
Perhaps the designer in the design of the time is really pure black and then overlay a certain amount of transparency to adjust the gray effect, but in fact the display of the UI does not need to reveal the underlying background, then the system in the process of rendering wasted a transparent mixed calculation. In this scenario, the best way is to let the designer give the exact color value directly (using #ffbfbfbf instead of #BF000000)
3. Find the key path that lets you animate the drop frame!
In the 2nd we solved the problem of the average frame rate of the whole animation, but there is still a smooth animation (fps>40), but in the animation process stuck a bit of the situation, we need to find out in the moment of this dropped frame what happened.
Tool 3:traceview
To do: Dig a hole to write
Here is an example of a practical analysis of the lag to see the simple use of this tool.
e.g. Android 5.0 just out, on the Nexus 5 found the reader of a page Flip animation very card, so we first open a gfxinfo look at the general situation:
Uh... It is obvious that these sky-like bars are the cause of our lag, these single frames are far beyond the green callout line 16ms, so we need to find the next step to the specific code that causes these problems;
TraceView can record the execution time of each function block in your code over time, and you can see the execution time of some key methods of the system, which can be sorted in descending order to find the most time consuming code block.
Use the method can refer to here
You can focus on these two properties first:
Incl CPU time: A function takes up CPU times, including internal calls to other functions of the CPU time
EXCL CPU Time: A function consumes a CPU, but does not contain the CPU time that is consumed by internal calls to other functions
The red arrow above the green color block is represented by the red box below the Drawpostext method of time-consuming, you can see most of the time spent on the function of the execution, resulting in the above 3000ms ~ 4000ms between only more than 10 frames ~ Our ideal effect is this: a single time is short, 1s painted much
Well then we can find our own code from the Drawpostext caller layer below and navigate to the problem.
Luckily, it's my own code to go back to the first level. The reason is indeed that drawpostext is time-consuming to draw.
The next step is to look at the document for this particular issue, and finally found that the preview version of Androidl is not supported when the hardware acceleration is turned on, so just change the API to OK (of course, now the 5.0 version has fixed the bug, it can be used normally).
From this example we can simply see the use of TraceView in the process of performance analysis, can quickly locate the time-consuming operation, to help developers solve the problem. Using TraceView can be starttrace directly in eclipse or through debug.startmethodtracing () in the Code;
The former is easy to use, the disadvantage is to open the tracing of the mobile phone is compared card, will affect the actual judgment. The latter benefit is more accurate, that is, the use will be relatively troublesome.
P.s. Also from here we can see the drawbacks of turning on hardware acceleration mentioned in three. 1: Some APIs will fail on certain system versions, some specific ROMs, and you need to consider various compatibility issues.
4. Some other piecemeal optimization points:
Avoid and system status bar, virtual keys, input method to do animation;
This does not understand the root cause, but avoids this scenario as much as possible.
e.g. the application will be animated when switching to full-screen state, such as playing a menu panel. If this animation is not required to come out immediately, it may be a little bit 200ms, and so on the top of the status bar of the animation finished and then do the menu panel animation, will be much smoother.
E.g.2 Input Method top to hang an expansion slot/similar to QQ input box;
Since this interface is ejected with the input method pop-up, the fade-in animation of this interface will compare the card. Ibid, we wait a little more than 150ms, and other input method display after the beginning of our own animation, the effect is better.
Reduce the visual difference between the main object and the background of the animation, the closer the color, the more smooth the feeling;
This is the Qq browser novel reader, its page edge of the shadow effect is very light, because the body of the animation is a shadow, then it with the background of the lower visual difference, the more transparent shadow, then it will appear more fluent.
Visual effects of different animation curves
Under the same frame rate animation, different animation curves show the difference in visual effect is still relatively large. In the common displacement animation, the effect of acceleratedeccelerate acceleration and deceleration is usually more natural. Animation/animator's default interpolator is linear, so try a natural curve to experience a different effect.
Of course, you can write a interpolator yourself, and implement its Getinterpolation method to freely define your own animation interpolator.
In addition, the Android L has provided developers with a very useful pathinterpolator, which makes it easy to define special animation curves.
In addition, we recommend a gadget that previews the effects of different animation curves: The animation curve tool
You can easily adjust how a curve corresponds to the visual animation effect, and how to implement the curve on the interpolator need to study the Bezier curve or pathinterpolator.
Change the initial position/initial value of the animation to deceive the visual
This is a relatively tricky method, and at some point there will be a drop frame phenomenon, the individual is not very recommended, but in a specific scenario is still useful.
e.g. do a gradient animation, 200ms from scratch in the display:
Since our perception of transparency is very low, we can let the animation not start from 0%, but start with 30%, that is, we finish from 30% to 100% in the 200ms, so the animation will be smoother, the disadvantage is that the threshold control is not good, we will find that from 0%alpha to 30 %alpha's jumping.
Frame rate has been difficult to improve, the animation scheme:
Different types of animations arrive at a similar "smooth" frame rate requirement. The shorter the movement within the same time, the more slippery the natural.
Therefore, the motion animation has the highest requirement for frame rate, the rotation/scaling animation is the second, and the gradient animation has the lowest frame rate requirement.
If you find that the effect of a bottom pop-up menu is optimized to a headache compared to a card, or a bad performance on a low-end machine, it is highly recommended to change the pop-up animation to a fade-out animation, although the frame rate may be similar, but the visual effect is really very effective.
[Android] UI Performance Tuning Notes