apognu / otter

Music player for Funkwhale
MIT License
216 stars 21 forks source link

App is unresponsive with lots of favorites #2

Closed agateblue closed 5 years ago

agateblue commented 5 years ago

Hi, I've tried Otter on multiple pods, and it's working great, except on accounts that have lots of favorites.

Whenever I sign in with an account that has lots of favorites (~1000 during my test, but it may require less to trigger the issue), the app becomes completely unresponsive for me: I can't scroll, change tabs, open settings, etc.

In the background, otter is fetching for favorites (I can see the corresponding requests in the server logs). Even when the fetch is complete (no more HTTP requests sent), the app stays unresponsive.

I think it's related to the fact that Otter maintain a full cache of all the favorited tracks, which can be resource-hunghy with lots of tracks. It may be something else though.

A possible solution:

  1. When app is loaded, send a single request to /api/v1/favorites/tracks/all/ to retrieve the favorited track IDs and use this to power the favorite icon next to each track. This should be way faster and less resource-hungry, because you only need a single HTTP call, and only retrive a list of ids.
  2. When the Favorites tab is visited, fetch the first page of favorites (and have the same behaviour as on albums / artists / playlists tabs, with infinite scrolling

I'm not really sure about the Shuffle button on the favorite tab, maybe shuffle/insert the first page, then fetch/insert other pages in the background and reshuffle when it's done?

If you cannot implement everything, I expect step 1 to fix the issue by making the app usable (even if the favorites tab isn't).

Let me know if there is anything I can do to help :)

apognu commented 5 years ago

I was able to reproduce this.

For your point 1, the use of /api/v1/favorites/tracks/all was implemented in 1.0.10 and is used throughout the UI for the heart icons. As far as I can see, this is not the core issue anymore.

As you said, the issue stems from the necessity from any view that shows tracks (so, when inside an album, a playlist or the favorites) to load all tracks at once (the "Shuffle" or "Add to queue" need to have all tracks available). Other views can load items progressively as you scroll.

By default, the _pagesize used by the app is 50, which I believe is the maximum, but I reduced it to 10 in my testing environment. I have favorited 105 tracks on open.audio, which means I need to perform 11 requests to get all tracks (favorites are fetched when the app starts, not ony when you visit the tab), which stalls my system. And you might have more.

On the Web UI, you paginate the favorites page and use a concept of radio to play all of them, which does not allow for retrieving the whole list of tracks.

I'll think about ways to circumvent this, but the progressive modification of the queue according to load status might introduce race conditions between user action and playback state.

How many favorites do you have, so I can try and reproduce your use case?

apognu commented 5 years ago

As a temporary workaround, I might disable loading of the Favorite tab at launch, at least until we find a more permanent solution.

jqueuniet commented 5 years ago

I'm experimenting a similar issue, with 821 favorites.

agateblue commented 5 years ago

For your point 1, the use of /api/v1/favorites/tracks/all was implemented in 1.0.10 and is used throughout the UI for the heart icons. As far as I can see, this is not the core issue anymore.

You're right, I missed that. I guess it's coming from loading of favorites at launch time then.

By default, the page_size used by the app is 50, which I believe is the maximum, but I reduced it to 10 in my testing environment. I have favorited 105 tracks on open.audio, which means I need to perform 11 requests to get all tracks (favorites are fetched when the app starts, not ony when you visit the tab), which stalls my system. And you might have more.

I have 950 of them, but it's interesting because I don't think the UI is unresponsive because of the HTTP traffic. I can see 18 http requests being fired to the corresponding endpoints, and nothing after that, but the UI remains unresponsive.

Could it be possible that the fact of holding that many objects in cache/memory slow down the app?

As a temporary workaround, I might disable loading of the Favorite tab at launch, at least until we find a more permanent solution.

Indeed, that would be a good workaround to make other features usable until we come up with a solution :)

apognu commented 5 years ago

I was able to pinpoint the issue.

This is not related to network requests or memory consumption, but is actually caused by the embedding of a RecyclerView inside a NestedScrollView where Android struggles to compute the various sizes in the list.

I have not found a clean solution yet, so I will change the layout to bypass this issue for now. This should be available in the next update (tomorrow, I hope).

agateblue commented 5 years ago

Great news @apognu, I'll update and let you know if the issue is fixed when the release is pushed. Thank you!

apognu commented 5 years ago

And I found a solution to keep the same layout (more or less) without the performance penalty. So it should be OK. I'll let you know when it's pushed.

apognu commented 5 years ago

Update was published and should be available when Google finishes processing it.

By default, and until you can confirm the issue is fixed, the Favorites feature is disabled by default and can be togged through an Experiments setting on the Settings page (app restart is necessary when toggling it).

Please send me feedback on whether the issue is fixed on your side, but through my tests (~ 850 favorites on open.audio), I have no skipped frames whatsoever. But YMMV (let's hope not).

apognu commented 5 years ago

This should be fixed. Please reopen otherwise.

agateblue commented 5 years ago

I confirm this is fixed for me !