status-im / status-mobile

a free (libre) open source, mobile OS for Ethereum
https://status.app
Mozilla Public License 2.0
3.9k stars 987 forks source link

Android performance issues #16714

Open pavloburykh opened 1 year ago

pavloburykh commented 1 year ago

Status app has significant performance issues on Android. That is not really noticeable on Google Pixel, but you can see how it looks on Samsung Galaxy A52 (Android 12) specs: https://www.gsmarena.com/samsung_galaxy_a52-10641.php - it is quite good device.

https://github.com/status-im/status-mobile/assets/97245802/13a464da-33c6-4138-a8e3-712862762964

Steps:

  1. Create different types of chats/comunities
  2. Generate some chat history with different types of messages
  3. Scroll through chat history, interact with chat elements (composer, context menus, bottom sheets etc)
  4. Pay attention if performance is ok

Actual result: poor performance can be observed. Animation is laggy and twitchy.

Additional Information

Parveshdhull commented 1 year ago

Hi @pavloburykh, Thank you very much for reporting this issue. In https://github.com/status-im/status-mobile/pull/16433 for toast animations we started to use layout animations. And in the current version of reanimated layout animations are not that stable and causing weird problems like https://github.com/status-im/status-mobile/issues/16693.

Please can you confirm if performance issues happen just after the start of the app, or after a few toasts are shown (like contact request accepted, etc.). If issue only happens once toasts are shown, please can you try build from https://github.com/status-im/status-mobile/pull/16729 and check if issue also present there.

pavloburykh commented 1 year ago

Hi @pavloburykh, Thank you very much for reporting this issue. In #16433 for toast animations we started to use layout animations. And in the current version of reanimated layout animations are not that stable and causing weird problems like #16693.

Please can you confirm if performance issues happen just after the start of the app, or after a few toasts are shown (like contact request accepted, etc.). If issue only happens once toasts are shown, please can you try build from #16729 and check if issue also present there.

Hi @Parveshdhull! Thank you for looking at this issue.

I have checked build from https://github.com/status-im/status-mobile/pull/16729 and can confirm that performance issues still exist. It doesn't seem to me that issue is related to toast appearing as interface starts lagging even without toasts being shown.

@Parveshdhull sorry that I didn't help much. I will try to investigate in future to understand what exactly causing the issues. Cause for some time after app is just being opened performance seems to be ok but after scrolling chat history which contains images, link previews, long messages - interface starts lagging.

Here is a video recorded on build from https://github.com/status-im/status-mobile/pull/16729

https://github.com/status-im/status-mobile/assets/97245802/8abb6c41-9080-4c8b-9194-fcd4776af72c

Parveshdhull commented 1 year ago

Related information: https://www.notion.so/App-Performance-a9ad728b6bf4449ba3a394241e406524

Parveshdhull commented 1 year ago

Update

Flashlist

As mentioned in the above notion document, the app works well after opening, but after some time performance starts to degrade. So it might be related to high memory usage and leaking.

The article (https://www.bam.tech/article/measuring-react-native-performance-with-flashlight) compares performances of flash-list and flat-list and shows a significant decrease in memory usage. So I tried this library in our app and found out some limitations of this library.

1. Blank spaces

How does flash-list improve the app performance?

Unlike FlatList, FlashList uses recycling. Basically items do not get unmounted-remounted anymore, instead items disappearing from the screen are reused for new items appearing by changing their prop.

For this, We need to provide a prop estimatedItemSize to flash-list

estimatedItemSize is a single numeric value that hints FlashList about the approximate size of the items before they're rendered. FlashList can then use this information to decide how many items it needs to draw on the screen before initial load and while scrolling.

The value for this number is suggested(if not provided) and printed in metro logs by the library as a warning message.

But this technique for improving performance is causing blank spaces when scrolling fast in our chat screen as shown in the below video. (even with small estimatedItemSize)

Video
https://github.com/status-im/status-mobile/assets/17097240/3c45f15d-bad2-4a8c-b97a-b3f5cb9affcc

https://github.com/Shopify/flash-list/issues/868#issuecomment-1702471170 mentions that flash-list has these problems when we have different sizes of items in list (as in our case, messages, image, links etc.) Also https://github.com/Shopify/flash-list/issues/618 mentions the problem with fast scrolling and for that recommended solution is to optimize the items/components. More details on optimzation.

2. Problem with columnWrapperStyle

Our current implementation is not working well for jump-to screen when migrating to flash-list as columnWrapperStyle don't work for it.

Screenshot

There is probably a work around for this issue, by adding required margins etc in cards itself. Currently we are just using justify-content :space-between, to create same effect we need to use screen width and card size etc. Issue is fixable but further complicates implementation.

From initial implementation it didn't looked like there was much drop in memory usage by using flash-list. And we also need to optimize components to get rid of blank spaces and might need to decrease scroll speed etc. Not sure if all these will fix the issues thougs.

Memory consumption

Currently memory consumption is very high, and with every close and open of chat screen it keeps adding up, as can be be seen as ladder like pattern in below screenshot.

Screenshot

While trying to find out which component is causing this problem, I tried to remove 1 by 1 big components and measure increase in memory consumption using flash light, these were results. (while opening and closing of 1-1 chat 10 times)

Extra, Only removing composer = 90 MB Increase

These results are not sufficient enough to tell why memory is not freeing after closing the screen. This pattern was also visible with native navigation, surprisingly same 175 MB Increase.

While using flashlight we need to consider its not reliable way to measure as it can give varying results based on device environment and resources. I also tried to use leak-canary using flipper, but for some reason my app is not being detected by it.

Improvement Scope

Navigation

How we differ from native navigation?

Some of details about navigation can be found in this notion document.

First what's common. Similar to our navigation system, native navigation also keeps previous screens rendered and active re-frame subscriptions active in the background.

And What's different

  1. React Native Tree Size - Native navigation pushes native screen while navigation and renders new React Native Root inside that. Smaller tree size helps updating components etc. This is the major drawback of our custom navigation we are not able to fix.
  2. Animations - As Native navigation don't allow that much customization, there animations are somewhat simple.

Example, if we open a community chat from switcher card Native navigation - Just pushes a chat screen with simple slide animation from right or bottom Shell navigation - Opens chat screen with a zoom animation from a particular point in screen (switcher card position), with animating position, width, height, border radius etc. And in the background we open community screen, open community home, update switcher card position.

So, as we can see there are so much going on in case of shell navigation which we have to keep if we want to keep all the perks of jump-to navigation and cool animations.

Ok, that was limitations, now let's discuss what is better(or can be).

As shell navigation is custom navigation system it gives complete freedom to us for improving performance. Currently we are destroying and recreating screen while navigating. But if we optimize and simplify screens enough, we can keep them rendered. This is the main thing which makes flash list and our bottom tabs implementation have very good performance. If we are not re-mounting big and heavy components like composer, navigation bar, loading skeleton etc. every time it can significantly improve chat opening time, which is not possible with native navigation system and causes stumbled opening of the screen.

Things we should do to improve performance

pavloburykh commented 1 year ago

@Parveshdhull many thanks for this detailed research.

pavloburykh commented 9 months ago

UPDATE (25.01.24):

Just a small update related to performance on my Android 12, Samsung Galaxy A52.

When recovering accounts that have a lot of data (communities with history, many contacts etc) I am still facing serious performance issues. On the video below you can see how laggy is the UI when scrolling the history, interacting with app elements etc. Such level of performance in fact makes the app hardly usable for future android users.

I understand that this problem is very hard to debug and resolve but I would like point out that this is a potential critical issue in terms of public release. So it is necessary to improve it.

https://github.com/status-im/status-mobile/assets/97245802/7bd06272-dece-4ad1-8233-644077d52388

cc @cammellos