dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.06k stars 1.73k forks source link

[Android] CollectionViewwith multiple bindable layouts (CardWithComplexContent) performance issues #21580

Open eth-ellis opened 6 months ago

eth-ellis commented 6 months ago

Description

When migrating our app from Xamarin.Forms to .NET MAUI we noticed that for most of our CollectionViews the performance when scrolling was worse.

When new views appeared the CollectionView would stutter/jitter resulting in an unpleasant user experience.

Our item templates are somewhat complex but still worked great in Xamarin.Forms.

In the linked repro apps, we have a template called CardWithComplexContent which is somewhat similar to the template in our app.

Note

Android (Samsung A73) - Xamarin.Forms

https://github.com/dotnet/maui/assets/13865151/25eac924-a499-4908-afd9-ab7108d71437

Android (Samsung A73) - MAUI

https://github.com/dotnet/maui/assets/13865151/cd402208-674f-4cd4-8a67-b3038e1e8f88

iOS (iPhone 6s) - Xamarin.Forms

https://github.com/dotnet/maui/assets/13865151/13a64912-3daf-4325-9d0e-4c15d4cee2eb

iOS (iPhone 6s) - MAUI

https://github.com/dotnet/maui/assets/13865151/d46972ec-5e51-479d-aa53-81351874db9e

Steps to Reproduce

  1. Checkout .NET MAUI and Xamarin.Forms repro projects.
  2. Build and deploy the apps to your devices in Release configuration.
  3. Run both apps and select either the CardWithTheLot or CardWithComplexContent template.
  4. Compare scrolling performance on both apps (fast scrolling and slow scrolling).

The apps contain other templates for attempting to isolate elements which impact performance the most.

Accepting PRs or suggestions on the repro app repos for templates to add for comparison.

Acceptance Criteria

The scrolling experience on .NET MAUI performs as well as or better than Xamarin.Forms for all affected platforms.

Link to public reproduction project repository

https://github.com/eth-ellis/Issue-Repro/tree/main/CollectionViewPerformanceXamarin and https://github.com/eth-ellis/Issue-Repro/tree/main/CollectionViewPerformanceMaui

Version with bug

Nightly / CI build (Please specify exact version)

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

iOS, Android

Affected platform versions

No response

Did you find any workaround?

No response

Relevant log output

No response

Matt-17 commented 6 months ago

Unfortunately I must agree. I just put 100 same size labels in one collectionView and it's stuttering on my Pixel 5. In Forms this was totally fine. My workaround is now putting this in VerticalStackLayout and ScrollView as I don't need the other extras. I loads slower, but better than this scrolling experience. Bonus points: put this CollectionView inside a CarouselView and you're crying.

jonmdev commented 6 months ago

Thank you for making this thread and providing such objective evidence. Your post clearly shows this is a Maui problem.

I have been struggling with this problem as well. I even built my own version of a "CollectionView" which performs similarly poorly. I have also created simple simulations of translation/update of elements to try to figure out the issue, all of which behave the same.

I have tried two methods of creating/simulating my own "CollectionView" type function in Maui:

1) Having 10-15 elements that each translate directly themselves together on screen and then wrap top to bottom to simulate scrolling. I posted a simple simulation of this nature here. The elements are derived from AbsoluteLayout and hold each only Border/Image/Label elements.

2) Having 10-15 similar elements on a large AbsoluteLayout as a base which translates (so I am not translating the elements themselves each frame but rather their big parent AbsoluteLayout) and then wrapping/updating the necessary elements only as they hit screen top or bottom.

In both cases the performance on Android has been identical to what you show in your videos. Even if I simplify the display elements so they are just a few labels on an AbsoluteLayout, Android struggles to update them effectively in Maui. I can't build release iOS versions to compare.

Given I can reproduce the same stuttery "scrolling" even with simple creations made of nothing more than AbsoluteLayout, Image, Label, and Border with very simple updates, I suspect the problem is more generalized in Maui than the CollectionView.

I suspect it has something to do with Maui invalidating the platform views in a way that is making them redraw the screen too many times when even simple updates occur. There is clearly way too much effort going on. Translations should be extremely cheap to adjust and Label text updates should also be very simple. Yet they are not. Simple things like this cause the apps to grind down. Watching the Android Studio profiler when I load a test APK, I can see it is doing too much work each update but don't know why.

Hopefully your evidence will help lead to the cause and solution.

Zhanglirong-Winnie commented 6 months ago

Verified this issue with Visual Studio 17.10.0 Preview 2(8.0.14 & 8.0.0-rc.2.9530). Can repro on android and iOS platforms with sample project.

bcaceiro commented 6 months ago

I am converting all my collectionviews for BindableLayouts ( since I don't have that many elements) and the performance gains are huge.

On other note, one thing I noticed: Without interacting with the collectionview, the Garbage Collector is crying, spamming multiple GCs - which is kinda strange? (after loading the CV)

Alex-Dobrynin commented 6 months ago

this is all about new layout system in MAUI. xamarin forms used another layout system. if look into the code of collectionview in maui and in xf, they are pretty the same. but the layout system had significant changes not in a good way.

By the way, just created own virtualize listview based on scrollview and absolute layout. If somebody wants, can share the code. it does not use any row of native code.

this is android, on ios almost the same. also works on other platfroms

https://github.com/dotnet/maui/assets/23138430/182d5476-90e0-46fa-82b0-c475777148e1

MichaelShapiro commented 6 months ago

@Alex-Dobrynin I'd be interested to look at the code. Thank you.

jonmdev commented 6 months ago

this is all about new layout system in MAUI. xamarin forms used another layout system. if look into the code of collectionview in maui and in xf, they are pretty the same. but the layout system had significant changes not in a good way.

By the way, just created own virtualize listview based on scrollview and absolute layout. If somebody wants, can share the code. it does not use any row of native code.

I am confused and interested by your post. I also agree with you this is not a specific "CollectionView" issue but rather a general Maui issue. As I noted, I created my own "CollectionView" type systems, but they all performed equally poorly.

The problem cannot be directly in the "CollectionView" as you note, but rather inefficiencies in how Maui is updating the elements/layouts or invalidating the views and forcing excess redraws. Even if the only elements I use are AbsoluteLayout elements (containing a few Borders/Labels/Images) translating on an AbsoluteLayout base (simplest Layout system possible) the problem persists.

For example, @jonathanpeppers found one problem here with Labels being slow to update and fixed it: https://github.com/dotnet/maui/pull/21291

But I presume there are other major problems still. Do you know of any specific problem with the Layout that might be causing all of this?

Also are you saying you found a way to circumvent this? If the problem is with the core elements/layout system then I am not sure how it can be circumvented without skipping Maui altogether. Perhaps the problem is just not as visible with a simple custom ListView but without fixing the underlying cause it will still be there of course.

brentpbc commented 6 months ago

@Alex-Dobrynin I would also be very interested to view the code.

FM1973 commented 6 months ago

@Alex-Dobrynin me too

WebGoose commented 6 months ago

@Alex-Dobrynin me too

IrynaDoroshenkoDev commented 6 months ago

@Alex-Dobrynin looks pretty good and really fast!

Alex-Dobrynin commented 6 months ago

this is not finished version, but it supports different scroll orientations and device orientation change. still working on it.

VirtualizeListView.zip

Check in the release mode, debug is not smooth enough

By the way, it also can support 2d scroll, of course if you implement proper layout manager. for now only linear

mjsb212 commented 6 months ago

this is all about new layout system in MAUI. xamarin forms used another layout system. if look into the code of collectionview in maui and in xf, they are pretty the same. but the layout system had significant changes not in a good way.

I absolutely concur with the others here who are suggesting this has something to do with MAUI specifically and the Layout System. I have built my own CollectionView, and have also used 2 Third party versions (Telerik, Syncfusion) and I get the same exact results in every scenario. After doing all of that, and testing and profiling, and stepping through source... I can see there are issues with sizing and recycling when using certain layouts and templates -- most notably when using images and grid layouts in CollectionView; the performance is terrible when scrolling, no mater what vendor or version of CollectionView used. There have been a few existing open and backlogged issues about this for a while, and everything seems to be related, so I'm glad this is finally being looked in to.

AliKarimiENT commented 6 months ago

Hi,

I've been grappling with an issue that is significantly impacting the performance of our app, much to the frustration of the business owner. The problem lies with our Maui implementation, where we have a grouped list with headers and items, and a pagination feature to load additional data.

This performance issue is surprising to me, especially since I have prior experience with Flutter where I did not encounter such problems. In Flutter, we typically use a scroll view containing a ListView or Column, which automatically triggers data loading when the user scrolls to the bottom. However, attempting a similar setup in Maui has resulted in poor performance.

AliKarimiENT commented 6 months ago

this is not finished version, but it supports different scroll orientations and device orientation change. still working on it.

VirtualizeListView.zip

Check in the release mode, debug is not smooth enough

By the way, it also can support 2d scroll, of course if you implement proper layout manager. for now only linear

Did you handle paging in here too?

Alex-Dobrynin commented 6 months ago

@AliKarimiENT in this version no, this is just POC of smooth scrolling, but on my pc already added cells appering/dissapering functionality and load more. Need to edit layout manager to support this

AliKarimiENT commented 6 months ago

@AliKarimiENT in this version no, this is just POC of smooth scrolling, but on my pc already added cells appering/dissapering functionality and load more. Need to edit layout manager to support this

I reviewed the code but I think it will take time to add paging my self, and I will wait to maui update it.

Alex-Dobrynin commented 6 months ago

@AliKarimiENT maui will not update it, because this is my implementation. Maui can update only their collectionview

samhouts commented 6 months ago

Thank you for the detailed report and reproduction projects! We're investigating this particular issue, and we'll respond with any findings. CollectionView performance is one of our top priorities, so we are working on a variety of fixes that should positively impact most cases.

OvrBtn commented 6 months ago

Thank you for the detailed report and reproduction projects! We're investigating this particular issue, and we'll respond with any findings. CollectionView performance is one of our top priorities, so we are working on a variety of fixes that should positively impact most cases.

Hello, please keep in mind that even though MAUI's performance is worse in comparison to Xamarin, in case of CollectionView and ScrollView the performance in MAUI .NET 7 wasn't so bad. In .NET 8 it got much worse, check out https://github.com/dotnet/maui/issues/21554

Redth commented 6 months ago

There's a number of factors that may compound here causing this particular sample to be somewhat slower. We are continuing to investigate these and look at introducing fixes and improvements. Unfortunately this isn't a simple one change fixes everything.

What I can suggest in the meantime is making some changes to your XAML and data model to minimize scenarios that are going to impact performance. For instance, I made some changes to the original sample here: https://github.com/eth-ellis/Issue-Repro/compare/main...Redth:Issue-Repro:main

Generally having a bindable layout inside of a data template is not going to be a fast thing to do. I understand that it worked reasonably well in Xamarin.Forms, and we will be able to get there with MAUI too but for now, a bit of compromise and optimization of your layouts would help unblock this scenario.

Alex-Dobrynin commented 6 months ago

@Redth you gave just temporary workaround. It takes a lot of time to do such changings in the templates for each list in the app. For example in my app I have a lot of lists, each page with the list with specific data and different templates for the same data types, and regular ListView or CollectionView are suffocating to process my templates and data there.

But here the updated version of the VirtualListView I provided above, where it is much much performant then regular ListView and even CollectionView. And I'm sure it can be optimized much more, but I don't have enough time to play with it, for me it is enough of scrolling performance. And as you can see, there is no any platformspecific code for laying out the items. And because of that it works on all platforms out of the box without specific renderers (handlers) (except android for overscroll).

VirtualizeListView.zip

Also, you can write custom data adapter for grouped lists, and it is easy to add there sticky headers. Also you can add there grid items layout manager, for now only linear. And it supports both orientations and even neither, when user wants to disable scrolling.

Just give it a try and play with it. may be you can take this idea to write your implementations for new CollectionView or optimize this one. But existing CollectionView is overengineering and should be rewritten completely.

Phenek commented 6 months ago

I can confirm

I am working on my own DataGrid with CollectionViews (no infinite scroll only pagination). And I can give you some point of view.

My main ViewModel got the classical ItemsSource

        ItemsSource = new ObservableCollection<RowViewModel>();

each Row got it's own ViewModel

To get to the N page I got two solutions to replace the Items

1. create a local and affect ItemsSource.

var rowViewModels = new ObservableCollection<RowViewModel>();
... //foreach
rowViewModels.Add(new RowViewModel(row, index++)
...
ItemsSource = rowViewModels;

2. Or add directly to the ItemsSource

... //foreach
ItemsSource.Add(new RowViewModel(row, index++)
...

I have encountered latency issues with rendering, causing the screen to freeze my loader. If my loader freezes, it's because the MainThread is handling too much work...

The third approach

However, I found a third approach that works quite well instantly and does not freeze my loader!!!! In my RowViewModel, I have a main object, let's call it Monkey, which raises a PropertyChanged event for each property of the MonkeyRowViewModel.

public class MonkeyRowViewModel : BaseViewModel
{
    public MonkeyRowViewModel(Monkey monkey, int index)
    {
        Monkey = monkey;
        Index = index;
    }

    public Monkey Monkey
    {
        get => _monkey;
        set
        {
            _monkey = value;
            UpdateAll();
        }
    }

    public string MonkeyName => Monkey.Name;
    ...
    internal void UpdateAll([CallerMemberName] string name = null)
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        var elementType = GetType();
        foreach (var prop in elementType.GetProperties())
            if (name != prop.Name)
                changed.Invoke(this, new PropertyChangedEventArgs(prop.Name));
    }

Now in my Main View Model rather than creating a new ItemsSource I just change the Monkey Object of each Sourced Items

foreach (MonkeyRowViewModel vm in ItemsSource) 
    vm.Monkey = ApiResults.Monkeys.ElementAt(index++)

And this is very fast because I recycle the RowViewModels, I simply change their internal Monkey objects! Under the hood I prevent the collectionView of pushing new/recycled views on the screen.

So the main problem is not the Bindings!

Now it could arise from two main reasons:

1. How CollectionView assign/managed sourced item with new/recycled View.

2. How .NET MAUI render Views on the screen, even with already constructed Views.

The example provided by @Alex-Dobrynin suggests the first reason.

But in another scenario, i suggest the second.

When I want to push a complex View (kind of a popup) in a Grid for example and I use a button to Add/Remove this popup View from the Grid. I can remove the View pretty fast. But adding the View to the Grid depends if your finger is align with the stars ✨. It can be very fast (less than 300ms) or pretty slow (more than 600ms)

Both reasons seems related

@Redth @samhouts @PureWeen and the all team Thank you for your time ❤️

jonmdev commented 6 months ago

There's a number of factors that may compound here causing this particular sample to be somewhat slower. We are continuing to investigate these and look at introducing fixes and improvements. Unfortunately this isn't a simple one change fixes everything.

What I can suggest in the meantime is making some changes to your XAML and data model to minimize scenarios that are going to impact performance. For instance, I made some changes to the original sample here: eth-ellis/Issue-Repro@main...Redth:Issue-Repro:main

Generally having a bindable layout inside of a data template is not going to be a fast thing to do. I understand that it worked reasonably well in Xamarin.Forms, and we will be able to get there with MAUI too but for now, a bit of compromise and optimization of your layouts would help unblock this scenario.

I have not had a "bindable layout inside a data template." I am just doing straight C# and my basic label and translation updates are very slow causing similar lag and delays I don't get with similar builds in .NET Andorid. I think this is a very generalized and broad problem that runs through Maui. As you said, there are likely numerous issues.

I hope you can work on general fixes that will help us all. We all need the fast smooth scrolling users expect and every other UI system provides.

jonmdev commented 6 months ago

So the main problem is not the Bindings!

Now it could arise from two main reasons:

1. How CollectionView assign/managed sourced item with new/recycled View.

2. How .NET MAUI render Views on the screen, even with already constructed Views.

The example provided by @Alex-Dobrynin suggests the first reason.

But in another scenario, i suggest the second.

When I want to push a complex View (kind of a popup) in a Grid for example and I use a button to Add/Remove this popup View from the Grid. I can remove the View pretty fast. But adding the View to the Grid depends if your finger is align with the stars ✨. It can be very fast (less than 300ms) or pretty slow (more than 600ms)

Both reasons seems related

@Redth @samhouts @PureWeen and the all team Thank you for your time ❤️

There may be multiple reasons all at once, so maybe all these things are true. But I can absolutely agree and verify "bindings" are not the primary issue. I don't use bindings/XAML at all and still see terrible scroll performance in my custom C# "CollectionView" type design (which works blazingly fast and smooth in other non-Maui systems).

I manage my own reassignments of elements. From a C# perspective this is basically instant by stopwatch as this is very simple code in my system. So again, perhaps that is poorly done in Maui CollectionView, but it is not also the main issue.

2. How .NET MAUI render Views on the screen, even with already constructed Views.

This is the primary issue without a doubt. Although I don't want to share my real proprietary code and systems (and they are baked in deep into my projects anyway to excise), I have already posted a simple "autoscroller" that this is the case and can do more if needed.

The C# code that we have to control translation and updates updates can be virtually instant and take 0-1 ms by stopwatch, but Android will then struggle for multiple frames trying to render it all with each update at a terrible frame rate. The only theories or ideas I have:

All of this is generally invisible until you have something scrolling because that is the only time every millisecond counts.

This is a good example of the type of bug that is likely doing this:

https://github.com/dotnet/maui/pull/21291

@jonathanpeppers found that the label text updates were taking way too long because they were getting bogged down in something very slow they didn't need to be doing.

I think we need to evaluate the performance of the core functions for basic inefficiencies like this because that is where the problem likely derives from. ie. Working from the bottom up. Ensure every component can perform equivalently to Xamarin or native under pressure.

For example perhaps we should make .NET Android or Xamarin element torture test projects to compare against MAUI projects? I can make an infinite "autoscroller" in both that randomly updates the entries with labels, but this is only so useful as we don't have equivalent native Border. I don't know Xamarin so that would be a pain in the ass.

One needs to do torture tests of the basic elements against their native .NET or Xamarin equivalents before one can claim the issue is "CollectionView" and not primarily just bad performance in the basic elements. Eg. Have 500 Labels translating randomly on screen spamming with text updates also on a Timer set to 500 fps and see what you get on both for resulting deltaTime on the Timer as the system struggles.

AliKarimiENT commented 5 months ago

Besides this issue, we have faced a new one on release mode the GroupHeader binding mode doesn't work and we are surprised when we were getting ready to publish it.

Phenek commented 4 months ago

Furthermore, I would like to add that: When we change the source of an embedded Image on each items, the scrolling performance on iOS decreases drastically.

As most layouts nowadays require customized images for each item, it would be wise to optimize this aspect.

Equabyte commented 4 months ago

CV rendering performance does affect scrolling in a rather noticeable way, there's simply too much going on on the main thread in a non-optimized way; in connection with an API loader this is far from ideal because it freezes the scroll view when rendering the next bunch of items to display. This is a cross-platform issue causing poor user experience that should be somehow prioritized.

PureWeen commented 4 months ago

We've made a number of fixes in SR6

Still keeping this open for SR7 to continue tracking improvements.

If folks can test nightly on Android and report back that'd be helpful

Can you test with the latest nightly build? https://github.com/dotnet/maui/wiki/Nightly-Builds

Equabyte commented 4 months ago

Can you test with the latest nightly build? https://github.com/dotnet/maui/wiki/Nightly-Builds

Hi @PureWeen I just tested on Android with 8.0.60-ci.net8.24301.1 and in my case I can see no noticeable improvement. Let me also clarify the actual issue I'm facing with scrolling performance refers to the case of a CollectionView that requires items to be added incrementally as the user scrolls (think of news items read from some API, preloaded and buffered in a non-visible data structure and incrementally moved to a CollectionView). The issue is that, whatever solution I tried to adopt so far, adding (or changing) a few items to the CollectionView causes a short UI freeze that stops the scrolling until the rendering is complete. There seems to be no way to get the CollectionView to update in background while the scrolling happens, so even when I try to entertain the user with empty placeholder items, the scrolling is affected by the UI update in a rather annoying manner while the placeholders get replaced with the actual items. Loading the entire CollectionView prior to showing it to user is not an option in these cases, because the initial wait would take too long, so an incremental loading mechanism is recommended.

WebGoose commented 4 months ago

Can you test with the latest nightly build? https://github.com/dotnet/maui/wiki/Nightly-Builds

Hi @PureWeen

Just tested with 8.0.60-ci.net8.24304.1 and the scrolling is still very laggy / stutters a lot. It also takes a long time to render any changes when the data changes, sometimes a few seconds if there are more than 20 rows. The data load is almost instant as it's all fetched from a local DB on the phone, so it seems most of the delay is just re-rendering the collectionview.

This problem is mostly on Android. iOS is not perfect but it is a LOT faster.

Domik234 commented 4 months ago
Basic Info MAUI Version: 8.0.40 Configuration: Debug Important to set to .csproj: `false`
Layout info **CollectionView Test** Grouping enabled. DataTemplateSelector for HeaderTemplate, SubheaderTemplate, ItemTemplate. **HeaderTemplate** - Label (bigger - NunitoSansBold) **SubheaderTemplate** - Label (smaller - NunitoSansRegular) **ItemTemplate** - Grid Grid contains: - LeftView - TintedImage (Image with custom TintColor implementation) - Primary Text - One line only - NunitoSansRegular - Secondary Text - Two lines (filled with data from three string properties) -- First line 2 properties -- Second line 1 property -- NunitoSansRegular - RightView - Switching between TintedImage and Text **Layout - 3 columns, 2 rows - rowspan = 2 for LeftView and RightView** ![image](https://github.com/dotnet/maui/assets/9479585/ac55a971-5c5e-4fbe-a0ed-cea76a8803d2) **Examples** ![image](https://github.com/dotnet/maui/assets/9479585/f843a1d4-506c-43f3-8ac0-241b8ba34727)
Video (max 60 fps) [CollectionViewTest.webm](https://github.com/dotnet/maui/assets/9479585/56b9e255-124c-4c77-be6b-25f6f20a8d44)

Tested on Honor 20. This feels fluent (in earlier versions there were problems primarily on iOS). Propably greater problem on much complicated layouts or weak devices.

Note: CollectionView constructed in XAML but templates and items set in C# code. image

kimhongka commented 4 months ago

Im also having this issue with infinit loading more logic. Also, I need to load items on top of items as Im building a chat box. I have 5different templates like image, video and text templates. Im migrating Xamarin.forms app to MAUI and Xamarin version used Listview for it , worked fine, but listview with same template and logic in MAUI was soooo laggy and also the item appearing checking logic in Listview has a bug that it dose not return the visible first item correctly at scrolling with Listview in MAUI, so I have replaced it to Collectionview, it works reasonably well on Android, but the same codes in iOS is quite slow, the inital loading taking 1-2seconds and scrolling is really jumppy. The logic itself works as Android works, but it is really laggy in iOS.... Please provide us a solution on this, really want to see MAUI is a successor version over Xamarin. Thank you.

xyeie commented 4 months ago

When can we expect the performance issues of this collection view to be resolved? Please let us know. If it takes too long, we will need to switch to another cross-platform solution as soon as possible.

davidortinau commented 3 months ago

@xyeie @kimhongka @Equabyte @Phenek @AliKarimiENT please open an issue including a reproduction sample with your specific CollectionView related scenario. There's no one-size-fits-all issue or solution here, and we need focused issues to efficiently troubleshoot and provide solutions. Link this issue from the new issue if you feel they are related.

In reviewing the project on this issue I find that all the samples perform well when published to device with the exception of a ColV with multiple bindable layouts (CardWithComplexContent) on Android. That sample could possibly be improved on iOS as well, but it scrolls very smoothly and we'll need to profile it to see if there's actually any stutter.

Equabyte commented 3 months ago

@davidortinau you are right in tackling one issue at a time. The sample @eth-ellis provided with the complex bindable content cards should be good enough to start investigation and it may shed some light to CV rendering performance on Android in general.

KostGraz commented 3 months ago

Hello, thanks for working on the CollectionView. I'm sending you two videos that dramatically show the performance difference of the CollectionView between Xamarin and MAUI. It shows how when you click on "Search"

private async void SearchCommand(object sender, EventArgs e) { await Navigation.PushAsync(new GetOrderItem.GOIPage()); }

is called. In the GOIPage view model, a list of around 500 records is loaded from an SQLite DB and displayed in a CollectionView. In MAUI, this takes 15 seconds (!), in Xamarin, 15,000 records are loaded in less than a second. Since Xamarin is no longer supported, I urgently need a solution.

Best regards, Richard.

MAUI: https://github.com/dotnet/maui/assets/34093918/a24c1cf8-c870-4049-978d-b790703206f4

Xamarin: https://github.com/dotnet/maui/assets/34093918/e57dcbbb-8647-4f3d-b9ab-e2c81073cc5a

Xamarin with a list of 300.000 records: https://github.com/dotnet/maui/assets/34093918/b618d88e-61bc-4e55-b503-0697387c8cb5

Domik234 commented 3 months ago

Hello @KostGraz,

Have you tried disabling the interpreter using the <UseInterpreter>false</UseInterpreter> tag in .csproj? Have you tried to change ItemStrategy to "MeasureFirstItem"? (Looks like every item is the same size)

Is the layout of CollectionView items:

<Grid RowDefinitions="auto, auto" ColumnDefinitions="*">
<Label Grid.Row="0" Grid.Column="0" Text="...binding 1" />
<Label Grid.Row="1" Grid.Column="0" Text="...binding 2" />
</Grid>

? (I am worrying about usage of VerticalStackLayout)

Is this debug or release mode?

Have you tried to measure which process takes the longest time? (Maybe SQLite call can be slow too on .NET 8?) Have you used List or Collection with adding items by one?

KostGraz commented 3 months ago

Hello @Domik234 , thanks for the fast reply.

false : No. MeasureFirstItem: Yes The Rowdefinitions are auto, auto Yes, it is the Debugmode The items are added with "range". The SQLite works as fast as in Xamarin There is no delay in the debugable code.
Domik234 commented 3 months ago

@KostGraz thanks for the info!

The first step with UseInterpreter is the most important for speed if you don't want to use C# Hot Reload. For me it's like 5 times slower with this value set on true.

Other info I've asked is for potentional solving of MAUI team members. 😁

jonmdev commented 3 months ago

Just for reference, it seems @jsuarezruiz has recreated the same issue with another project here as of May 2024:

https://github.com/dotnet/maui/issues/22185

I am glad the team is recognizing the problem even if a solution is not immediately obvious. I think everyone would appreciate any help with it. This has been a continuously reported issue for a long time now.

As stated, I do not believe this is a specific "CollectionView" bug but rather just an issue of the Maui layout system overdoing things on every update. Hence you can see the massive spikes in resource utilization for each update on @jsuarezruiz's videos.

Thanks for any help.

CleverSoftwarePoland commented 3 months ago

Any news or solid workaround? Problem with CollectionView also affects CarouselView any CarouselView with collection is sluggish even with simple templates.

jonmdev commented 2 months ago

@xyeie @kimhongka @Equabyte @Phenek @AliKarimiENT please open an issue including a reproduction sample with your specific CollectionView related scenario. There's no one-size-fits-all issue or solution here, and we need focused issues to efficiently troubleshoot and provide solutions. Link this issue from the new issue if you feel they are related.

In reviewing the project on this issue I find that all the samples perform well when published to device with the exception of a ColV with multiple bindable layouts (CardWithComplexContent) on Android. That sample could possibly be improved on iOS as well, but it scrolls very smoothly and we'll need to profile it to see if there's actually any stutter.

On what objective basis are you drawing this conclusion? OP's samples were created on Release mode and clearly show the deterioration in scroll function that we are all complaining about. It is visible in iOS and Android. Can you not see it clear as day in the videos?

Are you suggesting this is not existing in the documented evidence there? You cannot see it in the videos or do not consider these videos important?

What standard is "perform well when published to device" when there is a clear and objective deterioration in function? Does this mean "when running on my high end test device faster than most users have and not under real world full app stress"?

I don't mean to sound rude, but I honestly feel like the primarily approach of the entire Maui team has been to gaslight us all about the poor layout performance issues both in iOS and Android for the past year.

No matter how many times anyone posts threads about it they are met with some combo of:

The problem clearly exists both in Android and iOS. Endless users are complaining about it. You have absolute objective evidence in the videos of the OP both for Android and iOS. @jsuarezruiz posted yet another Android project showing the issue clear as day with massive abnormal resource utilization in Maui layout.

I hope there is sufficient willpower to look at and fix the problem. I don't think there is insufficient evidence.

My theory remains that Maui is doing far too many layout calls on each update resulting in excess measurements and invalidating. This could be tested by overriding a platform view/handler and debugging out how many times on measure or something like that is called per update in Xamarin vs Maui in one of these test projects.

Either way every bit of performance counts for mobile. Not every user has a high end test device. We should not be accepting dramatic objective deterioration in rendering function in Maui from Xamarin.

If the layout system in Maui is running in circles, these circles should be found and fixed.

Thanks again for any help on this. It is becoming one of the biggest remaining Maui issues.

Alex-Dobrynin commented 2 months ago

Buy the way guys. I've already released v1.1.7 of my VirtualizeListView, you can find it here https://github.com/MPowerKit/VirtualizeListView I know it is not a silver bullet, but in some case it can save nerves and time.

maonaoda commented 2 months ago

Buy the way guys. I've already released v1.1.7 of my VirtualizeListView, you can find it here https://github.com/MPowerKit/VirtualizeListView I know it is not a silver bullet, but in some case it can save nerves and time.

Will it be able to change the correct size based on the binding of header,footer,item (this is still a serious bug in maui for ios, but has not even been fixed. :(

bcaceiro commented 2 months ago

I have to agree with @jonmdev .

On a positive note, there have been significat improvements over the last past months regarding dotnet maui development and state.

However, the performance for rendering elements, with or without CollectionView, can still be improved. The proof of that is the work that @jonathanpeppers has been doing, with performance improvements all over different aspects. Even yesterday I was looking about 2 more, that impact the performance of everyone's application. Wish there were more people focused on this, or perhaps, in the current or next release , be a bigger priority. there are samples everywhere. Or, instead, get low end devices and see what's going on.

bcaceiro commented 2 months ago

Since it is hard to share the code of our applications most of the times, would it be preferrable to have a centralized place, to submit all speedscopes to be analyzed in the future?

Alex-Dobrynin commented 2 months ago

@maonaoda yes, in this VirtualizeListView items can change the size based on binding context, also items can change size dynamically if the content size changes eg expander

CleverSoftwarePoland commented 2 months ago

I'm really struggling with performance problems on MAUI during our app migration from Xamarin I did create simple project representing mix of CarouselView and CollectionView showing performance problem. It's dead simple with two labels. https://github.com/dotnet/maui/issues/23715

jonmdev commented 2 months ago

I have forked the project from @eth-ellis and split it with my own edits to:

If you are working with the Xamarin project, be advised that you must keep it in a root directory (eg. C:\CollectionViewPerformanceXamarin) as Xamarin otherwise starts giving weird errors if the paths get long. See https://learn.microsoft.com/en-us/answers/questions/313806/why-am-i-getting-this-error-on-a-new-xamarin-forms

I have only just started but I will continue this approach as I have time.

Test Method

I put my custom code in folders called "MY CUSTOM CODE" so it is obvious what I did. So far, I just created an override for the Android Label class in Xamarin and Maui so I could debug out when an OnMeasure or LayoutUpdate occurred.

I'm sure there will be many more problems. However, this one was just quite crazy and hit me right in the face.

Problem 1 (Android): Maui project starts with an infinite measurement/layout feedback loop

Remember what I said about thinking the Layout system is the problem? 😂 When you start the Xamarin project this is what you get on debug:


[0:] MEASURE UPDATE 1 ID: 214177538
[0:] LAYOUT UPDATE 1
[0:] MEASURE UPDATE 2 ID: 214177538
[0:] LAYOUT UPDATE 2
[0:] MEASURE UPDATE 3 ID: 116333858
[0:] LAYOUT UPDATE 3
[0:] MEASURE UPDATE 4 ID: 47251612
[0:] LAYOUT UPDATE 4
[0:] MEASURE UPDATE 5 ID: 20679304
[0:] LAYOUT UPDATE 5
[0:] MEASURE UPDATE 6 ID: 100471506
[0:] LAYOUT UPDATE 6
[0:] MEASURE UPDATE 7 ID: 91589150
[0:] LAYOUT UPDATE 7
[0:] MEASURE UPDATE 8 ID: 57420330
[0:] LAYOUT UPDATE 8
[0:] MEASURE UPDATE 9 ID: 41598710
[0:] LAYOUT UPDATE 9
[0:] MEASURE UPDATE 10 ID: 112461799
[0:] LAYOUT UPDATE 10
[0:] MEASURE UPDATE 11 ID: 244608894
[0:] LAYOUT UPDATE 11
[0:] MEASURE UPDATE 12 ID: 42206602
[0:] LAYOUT UPDATE 12
[0:] MEASURE UPDATE 13 ID: 50488772
[0:] LAYOUT UPDATE 13
[0:] MEASURE UPDATE 14 ID: 77732400
[0:] LAYOUT UPDATE 14
[0:] MEASURE UPDATE 15 ID: 222734684
[0:] LAYOUT UPDATE 15
[0:] MEASURE UPDATE 16 ID: 105054024
[0:] LAYOUT UPDATE 16

This means there were 16 label measurements and 16 label layout updates. (I am just counting/incrementing up globally for each measurement/layout that occurs). The "ID" is the HashId for the label just for reference.

Totally normal. It stops there and stays idle.

By contrast if you start the Maui project it goes into an endless loop of measuring and laying out such that after a few seconds, we have already measured and laid out the labels thousands of times, and the Debug output is:


[0:] MEASURE UPDATE 2753 ID: 130619213
[0:] MEASURE UPDATE 2754 ID: 99036496
[0:] MEASURE UPDATE 2755 ID: 18898778
[0:] MEASURE UPDATE 2756 ID: 132098689
[0:] MEASURE UPDATE 2757 ID: 173764884
[0:] MEASURE UPDATE 2758 ID: 125422339
[0:] MEASURE UPDATE 2759 ID: 118667178
[0:] LAYOUT UPDATE 1221
[0:] MEASURE UPDATE 2760 ID: 130619213
[0:] LAYOUT UPDATE 1222
[0:] MEASURE UPDATE 2761 ID: 99036496
[0:] LAYOUT UPDATE 1223
[0:] MEASURE UPDATE 2762 ID: 18898778
[0:] LAYOUT UPDATE 1224
[0:] MEASURE UPDATE 2763 ID: 132098689
[0:] LAYOUT UPDATE 1225
[0:] MEASURE UPDATE 2764 ID: 173764884
[0:] LAYOUT UPDATE 1226
[0:] MEASURE UPDATE 2765 ID: 125422339
[0:] LAYOUT UPDATE 1227
[0:] MEASURE UPDATE 2766 ID: 116333858
[0:] MEASURE UPDATE 2767 ID: 116333858
[0:] LAYOUT UPDATE 1228
[0:] MEASURE UPDATE 2768 ID: 38820601
[0:] MEASURE UPDATE 2769 ID: 137909740
[0:] MEASURE UPDATE 2770 ID: 15590166
[0:] MEASURE UPDATE 2771 ID: 62381677
[0:] MEASURE UPDATE 2772 ID: 177567472
[0:] MEASURE UPDATE 2773 ID: 154763151
[0:] MEASURE UPDATE 2774 ID: 38820601
[0:] MEASURE UPDATE 2775 ID: 137909740
[0:] MEASURE UPDATE 2776 ID: 15590166
[0:] MEASURE UPDATE 2777 ID: 62381677
[0:] MEASURE UPDATE 2778 ID: 177567472
[0:] MEASURE UPDATE 2779 ID: 154763151
[0:] MEASURE UPDATE 2780 ID: 19362727
[0:] LAYOUT UPDATE 1229
[0:] MEASURE UPDATE 2781 ID: 38820601
[0:] LAYOUT UPDATE 1230
[0:] MEASURE UPDATE 2782 ID: 137909740
[0:] LAYOUT UPDATE 1231
[0:] MEASURE UPDATE 2783 ID: 15590166
[0:] LAYOUT UPDATE 1232
[0:] MEASURE UPDATE 2784 ID: 62381677
[0:] LAYOUT UPDATE 1233
[0:] MEASURE UPDATE 2785 ID: 177567472
[0:] LAYOUT UPDATE 1234
[0:] MEASURE UPDATE 2786 ID: 154763151
[0:] LAYOUT UPDATE 1235
[0:] MEASURE UPDATE 2787 ID: 130619213
[0:] MEASURE UPDATE 2788 ID: 99036496
[0:] MEASURE UPDATE 2789 ID: 18898778
[0:] MEASURE UPDATE 2790 ID: 132098689
[0:] MEASURE UPDATE 2791 ID: 173764884
[0:] MEASURE UPDATE 2792 ID: 125422339
[0:] MEASURE UPDATE 2793 ID: 130619213
[0:] MEASURE UPDATE 2794 ID: 99036496
[0:] MEASURE UPDATE 2795 ID: 18898778
[0:] MEASURE UPDATE 2796 ID: 132098689
[0:] MEASURE UPDATE 2797 ID: 173764884

It is endlessly spamming measurements and layouts. Slightly more than 2:1 measurements to layout updates. It will go up to the tens of thousands if you leave it.

You can break the feedback loop by scrolling down far enough. But this is absolutely insane on startup.

This provides some general evidence for the theory that the layout system is running in circles. Maybe if we are lucky it is just one point of failure affecting everything and fixing that loop will solve the rest.