is an entry in the " 2021 Umeng + Mobile Application Performance Challenge 161821e61e1032". This paper describes how the author uses the + U-APM tool to optimize performance.
As a countdown calendar APP, we need to display the countdown for each date in real time and accurate to the second. But when our app swipes to refresh the data, there will be a freeze.
Stuttering depends to a large extent on the device's CPU and other processes that consume CPU time. So we tried to use U-Meng + U-APM memory analysis to analyze the APP:
By observing the distribution of memory, the operation of most programs is within a predictable range, and we need to test more fine-grained.
Start Android Profiler Tool Window
, open CPU Profiler
and select the correct timeline. Connect our test device and slide to refresh again, you can see that the Profile thread is added to the application process and consumes additional CPU time. Take a look at Logcat
:
I/Choreographer: Skipped 147 frames! The application may be doing too much
View the CPU Profiler
timeline:
There is a view on the chart that represents the user's interaction with the application. All user input events are shown here as purple circles. You can see a circle, which represents the swipe we performed to refresh the data.
Under the event, there is a CPU timeline, which graphically displays the CPU usage of applications and other processes related to the total available CPU time. You can also view the number of threads the application is using.
At the bottom, you can see the timeline of thread activity belonging to the application process. Each thread is in one of three states indicated by color: active (green), waiting (color), or sleeping (grey).
At the top of the list, you can find the main thread of the application. On my device (Nexus 5X), it uses about 5 seconds of CPU time. We can record a method to track and view.
Click the "Record" button before swiping to refresh the operation and stop recording immediately after the data refresh is complete:
We will start the analysis from the chart displayed in the first tab. The horizontal axis represents the passage of time.
The caller and its callee (from top to bottom) are displayed on the vertical axis. Method calls are also distinguished by color, depending on whether to call the system API, the third-party API, or our local function. The total time of each method call is the sum of the method’s own time and the time of the callee:
From this chart, it can be inferred that the performance problem lies within the generateItems method.
In order to confirm our inference, we used U-Meng + U-APM for the online test. The test results are the same as the previous ones. The picture below shows the analysis test of U-Meng + U-APM 161821e61e1809. The figure shows the main methods that cause the high time consumption of the CPU and lead to the occurrence of the stuck situation:
The flame graph reveals which methods are taking up valuable CPU time and aggregates the same call stack:
Two suspicious locations were found, getRemainingTime
the execution time of the entire method reached more than 2 seconds,LocalDateTime.format
occupies more than 1 second of CPU time:
This time also includes the time period when the thread is not active. In addition, you can switch the timing information to be displayed in the thread time.
The chart in the last tab shows a list of method calls in descending order of CPU time consumption. The chart provides detailed timing information (in microseconds):
Obtain timing information for methods that consume too much CPU time from the graph. Associate them with two methods in the call stack:
class method total time (in ms) percentage of recorded duration
Sample1Activity refreshData 3027 89.28
Sample1Activity generateItems 3025 89.22
Sample1Activity getRemainingTime 1723 50.83
LocalDateTime format 1003 29.59
You can see that getRemainingTime
and LocalDateTime.format
consume more than 80% of the time. In order to solve the lag problem, we need to start from here.
So what should I do? Smart readers may have proposed several solutions. Since we have performed a lot of calculations, we will only call the getRemainingTime
and LocalDateTime.format
methods for a few items that are currently displayed and ready to be displayed.
In order to implement it, we need to update the Item property and save the necessary data for formatting later:
data class Item(val now: LocalDateTime, val offset: Int)
This requires the following changes to be applied generateItems
and bindItem
private fun generateItems(): List<Item> {
val now = LocalDateTime.now()
return List(1_000) { Item(now, it + 1) }
}
private fun bindItem(holder: ViewHolderBinder<Item>, item: Item) = with(
val date = item.now.plusDays(item.offset.toLong()).toLocalDate().atS
val remainingTime = getRemainingTime(item.now, date)
We inlined the createItem
function, and now all functions are inside the bindItem
method.
After our code modification takes effect, restart CPU Profiler
and record the operation of the method.
In order to check whether our optimization is successful, we need to check Call Chart
:
Move the generateItems
function 061821e61e1b56, and you will find that it takes about 0.3 seconds.
This reduces CPU time by more than 13 times compared to before optimization. To ensure that our changes will not bindItem
, we switch to the flame icon to check the total time-consuming of bindItem.
As shown in the figure, it consumes a maximum of 0.1 seconds:
In addition, we can conduct rolling tests to ensure that our code optimization does not affect the performance of the overall application, and record them during the rolling process.
The test found that there will be no more freezes and frame drops after scrolling. success! The code has been optimized!
summary
Android Profiler and U-Meng + U-APM are good test tools. If we pursue a smooth user experience, it is necessary to use these excellent debug tools. In this article, I mainly focus on performance tuning.
However, the memory analysis, OOF exception and memory Union + UA PM 161821e61e1c33, which are not covered in this document, are also worth studying. Recording memory allocation is very helpful for finding memory leaks, such as whether the bitmap is recycled in the code.
Regardless, the use of appropriate analysis tools can bring many optimization results, and we look forward to readers' self-exploration.
is an entry in the " 2021 Umeng + Mobile Application Performance Challenge 161821e61e1c69". This paper describes how the author U-APM has improved performance.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。