Analytics is an integral part of a modern mobile application. Analytics allows you to collect information about the user to develop and improve the product.
Often, gathering information reduces application performance. The process additionally loads the CPU and memory, and this is a high price. Slow operation of the application can cause negative user feedback, lower the rating and lead to loss of audience.
This problem was faced by our team of Android developers while working on the next project that was related to the news. We needed to register the display of each news in the list.
Attempt # 1
Having received the task of collecting analytics, the team quickly showed the result. The trigger for generating the event was chosen by the
onViewAttachedToWindow method. Everything seems fine, but with a quick scroll, the interface noticeably hung up - something went wrong. The problem had to be solved.
Everyone perceives a hang-up differently, so we needed facts and evidence. To measure the hanging, we chose the FPS indicator (Frames Per Second), and the FPS-meter
TinyDenser to measure the indicator. After connecting the utility, the team received an objective confirmation of the problem - the indicator fell, sometimes quite noticeably: less than 30 frames per second, the screen recording with the utility turned on is shown in Figure 1.
Figure 1. Screen capture before optimizationAttempt # 2
And if you postpone sending events until the user scrolls the list? “Hmmm,” thought the team, and decided to create a queue of events and send them after the scroll stops. Everything is simple: add
OnScrollListener to the
RecyclerView and wait until
newState is equal
SCROLL_STATE_IDLE - the task is partially solved.
class IdleStateScrollListener(private val analyticsFacade: AnalyticsFacade) : RecyclerView.OnScrollListener() { fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { analyticsFacade.setPending(newState != RecyclerView.SCROLL_STATE_IDLE) } }
The next step is to implement the accumulation of events and their sending.
To manage the queue, a class was created that was responsible for adding events to the queue and sending analytics to the service. For periodic submissions, we chose
ScheduledExecutorService with one thread that ran
Runnable every second, the time was chosen in an empirical way.
This immediately gave results, a significant increase in FPS. In principle, the problem was solved, in Figure 2 we see the result of the application after the second attempt. But only one task remained - the events were sent to the service, which led to the frequent generation of objects of the
Intent class, and this additionally loaded the
GC and delivered “pleasures” in the form of
stop-the-world pauses.
Figure 2. Screen recording after the second attemptAttempt number 3
“Sending more than one event at a time, but a list of events is another great idea,” the team thought. After a short revision of the class, the team implemented the sending of events in a list and received stable values of the indicator at the level of 55–60 frames per second (Figure 3).
Figure 3. Screen capture after third attemptfindings
The trivial task of collecting analytics has become an interesting and cognitive process, during which the team has mastered their skills in researching application performance problems and finding ways to solve them. I hope our experience will be useful for both beginners and experienced developers.
Could anything else be done?
Our team focused on the third option, but this is not the only thing that could be applied.
In the current implementation, when the
onViewAttachedToWindow method is triggered, the
news is transformed into an analytics event object, respectively, a new object is created. One of the possible solutions is to postpone the conversion until the moment of sending: to accumulate in the queue not the events, but the elements of the list themselves. Then the conversion will occur when the scroll will be in
SCROLL_STATE_IDLE mode. Also for events it was possible to create a pool of objects. In combination, these actions can give an additional performance boost to the application.