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.23k stars 1.76k forks source link

[Android] CollectionVIew scrolling performance on MAUI lags compared to XF #18505

Closed PureWeen closed 7 months ago

PureWeen commented 1 year ago

Description

Given the following layout

<ContentPage>
     <CollectionView x:Name="cvGrid" Background="Yellow" HorizontalOptions="Fill"
                             BackgroundColor="Black">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <Grid BackgroundColor="Purple" ColumnDefinitions="25,25,25,25,25,25,25,25,25,25,25">
                    <Label Grid.Column="0" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="1" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="2" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="3" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="4" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="5" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="6" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="7" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="8" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="9" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="10" TextColor="White" Text="{Binding Symbol}"></Label>
                    <Label Grid.Column="11" TextColor="White" Text="{Binding Symbol}"></Label>
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

the performance on XF is much better than MAUI

Steps to Reproduce

Run the following projects on Android and you'll notice that the scrolling on XF is super smooth compared to MAUI. If you perform really fast scrolling, XF remains smooth whereas MAUI starts to glitch and slow down.

MAUI: MauiCollectionView.zip

XF: XFCOllectionView.zip

I didn't test this on WinUI/iOS yet but it would be good to validate there as well

Link to public reproduction project repository

No response

Version with bug

8.0.0-rc.2.9373

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android

Did you find any workaround?

No response

Relevant log output

No response

Related Issues

https://github.com/dotnet/maui/issues/20433 https://github.com/dotnet/maui/issues/19933 https://github.com/dotnet/maui/issues/20797

Amir000001 commented 1 year ago

this problem also exists in net 7

PureWeen commented 1 year ago

Related https://github.com/dotnet/maui/issues/17326

mattleibow commented 1 year ago

Just tested iOS, wow, much slow.

mjsb212 commented 1 year ago

I'm having a similar problem with GridItemsLayout and described what I've tried/found in: https://github.com/dotnet/maui/issues/17326 -- Does anyone know if the issues are related??

Alex-Dobrynin commented 12 months ago

@PureWeen I have noticed that CreateContent() of datatemplate is much slower than in XF, may be here is the problem. because the same template in XF takes 30 ms to create and 200 ms in MAUI. I supposed that MAUI should be much performant than XF but it is not

mikebikerider commented 12 months ago

I observed CollectionView sluggishness in MAUI .NET 7, and even more with .NET 8 iOS compared to Xamarin forms. Multiple issues with grids not resizing properly. Star columns and rows do not behave as expected. I moved a big Xamarin iOS project to MAUI .NET 7, I will not publish it. Will keep updating Xamarin.Forms version. With Android it is even worse. Resizing issues worse than with iOS, CollectionView scrolling slower and jerkier. My Android Xamarin.Forms apps run faster than iOS counterparts. MAU Android apps significantly slower than MAUI iOS. Waiting for .NET 8 was a big disappointment. It brought further performance degradation instead of improvement. I like MAUI coding, but MAUI GUI performance is not acceptable.

BaY1251 commented 11 months ago

any plan for it?

Redth commented 11 months ago

It's worth noting that if anyone is looking at the speed of scrolling in CollectionView or ListView while debugging their app through Visual Studio, it is definitely going to be slower than on an actual release build. The reason for this is there's a lot more visual tree interaction happening with the live visual tree tooling which slows things down significantly.

Having said that, it does seem like it might be slower than it could be on Android even in a release build. I'm working on collecting some traces so we can look at the details a bit more and see where time is being spent.

Redth commented 11 months ago

Here's a speedscope trace from this app running on a Pixel 4 in release mode... dotnet-dsrouter.exe_20231205_163422.speedscope.json

Here's a video of the app running: https://github.com/dotnet/maui/assets/271950/f97cfdf8-631b-4a26-8386-1cc4f40c33bf

I think this is running reasonably fast looking at the video, and nothing stands out too much from the speedscope trace.

@jonathanpeppers thoughts?

Alex-Dobrynin commented 11 months ago

@Redth as i said before, CreateContent() method of DataTemplate is much slower in MAUI than in XF on same templates both in debug mode. in XF it takes 20 -30ms to construct template, in MAUI takes 200 ms. Maybe this is the case

jonathanpeppers commented 11 months ago

The CreateContent() method is showing a small % in the .speedscope file above:

image

When looking for low-hanging fruit while scrolling, I tended to look for things in the 2% range. But there still could be something done here that would help.

I added this section, as this seems to be coming up a lot:

jonathanpeppers commented 11 months ago

One thing I do see, I think we could completely eliminate this call:

image

Where it only calls into C# from Java if the TextView.Text is a "formatted string". So plain strings could avoid the interop.

mikebikerider commented 11 months ago

@Redth, is it worth comparing scrolling in CollectionView or ListView in release mode to scrolling of CollectoinView or ListView in Xamarin.Forms in any mode? I moved a 5 years old Xamarin.Forms project to MAUI .NET 7. Xamarin.Forms ListView and CollectionView scrolling on a physical device (Samsung Galaxy S20) is smooth and fast even when run in Visual Studio debugger with Hot Reload enabled. The MAUI app scrolling is slower, and it is jerky when running on the same device in release mode directly. Pretty much same on iOS, only Android is worse. I think there is more than one cause for poor performance. MAUI Grid.

From Microsoft online documentation https://learn.microsoft.com/en-us/dotnet/maui/user-interface/layouts/grid?view=net-maui-8.0

Caution Try to ensure that as few rows and columns as possible are set to Auto size. Each auto-sized row or column will cause the layout engine to perform additional layout calculations. Instead, use fixed size rows and columns if possible. Alternatively, set rows and columns to occupy a proportional amount of space with the GridUnitType.Star enumeration value.

Somehow in Xamarin.Forms using 'auto' rows and columns did not cause problems I could notice, and Xamarin.Forms Star rows and columns resize as documented. Not in MAUI .NET 7 or .NET8. Star columns and rows behave like 'auto' and that affects controls they are hosting, and controls that are hosting grid cells. ListView and CollectionView in my apps use one-row multiple columns Grid in the DataTemplate. One of the columns is always Star. Other columns width is bound to datasource (List<>). In Xamarin.Forms it works like a charm. In MAUI works too but does not resize properly when device is rotated. The app has 7 pages that have either ListView or CollectionView. In theXamarin.Forms app none of the pages has OnSizeAllocated(). I can rotate the device and everything including CollectionView/ListView resizes correctly. In MAUI the same XAML and code behind produce wrong sizing on load and when device is rotated and not just for CollectionView. In MAUI I had to write OnSizeAllocated() for each page to make it look more or less right, like I did in early Xamarin days. I tried .NET 8 when it was released in November. It is so much worse I went back to .NET 7. The added MAUI code is different between iOS and Android projects. Xamarin.Forms beats MAUI in the 'write code once' area too. If I would not have the Xamarin.Forms app in respective app stores since 2018 and vastly outperforming the MAUI version I might even publish the iOS version. Android still requires some work. But it makes no sense.

jonathanpeppers commented 11 months ago

is it worth comparing scrolling in CollectionView or ListView in release mode to scrolling of CollectoinView or ListView in Xamarin.Forms in any mode?

That's why we added the section at the top here: https://aka.ms/profile-maui#feature-xyz-was-faster-in-xamarinforms

Compare Release vs Release.

mikebikerider commented 11 months ago

Jonathan, in my experience the Release against Release comparison is hugely in favor of Xamarin.Forms. Microsoft MAUI .NET 7 and .NET 8 update notes always refer to improvements (in tests) against previous MAUI versions, The sad thing is I like MAUI coding. I don't like the result, and the ugly tweaks I do to keep layouts intact, more or less, when the screen orientation changes.

jonathanpeppers commented 11 months ago

@mikebikerider can you share a sample app, .nettrace, .speedscope where we can take a look? (and file a new issue)

It sounds like we need to just profile your MAUI app and see what it's doing.

mikebikerider commented 11 months ago

Jonathan, I have to write a sample app. If I do something terribly wrong that should affect both iOS and Android, right? Below is a flyout page with a CollectionView that my code loads from another flyout page.

Screenshot_20231207_131110

I issue a call from the previous page: await Shell.Current.GoToAsync("//assets",false); assetsPage.LoadAssets(listedassets, w, Width);

In MAUI iOS the page loads almost immediately. Under Android the calling page freezes for about 30 seconds, before the next page appears. Apparently, under Android await does not wait long enough for the page to load to the point it can start processing GUI code. Everything in MAUI Android seems be slower than in MAUI iOS. So, I do a trick, I call the loading code from a Timer. It kind of works, but first the user sees a mostly blank page: Dispatcher.StartTimer(TimeSpan.FromMilliseconds(500), () => { assetsPage.LoadAssets(listedassets, w, Width); return false; }); I don't need that trick next time I get to the page during the program run, but it is still ugly.

My Xamarin Android apps run faster than their iOS equivalents and code behind is identical except for the platform-specific calls. Not so with MAUI. MAUI iOS GUI updates are faster compared to Android, and I can't use the same common code. So far Xamarin renders do much better job.

jonathanpeppers commented 11 months ago

Did you profile this app? File an issue with some .nettrace or .speedscope files, thanks!

mikebikerider commented 11 months ago

@Redth is right about the release mode. CollectionView scrolling in Android release mode is faster. With Xamarin I could not tell the difference between my app running in the debug mode and release mode. It is different with MAUI. Thank you.

jonathanpeppers commented 10 months ago

@Redth is right about the release mode. CollectionView scrolling in Android release mode is faster. With Xamarin I could not tell the difference between my app running in the debug mode and release mode. It is different with MAUI. Thank you.

This is because Debug has the Interpreter on (for C# Hot Reload). Details on this here. The Interpreter didn't exist (or was experimental) in the Xamarin days.

jonathanpeppers commented 10 months ago

We reviewed the app here in our weekly performance meeting, and there is a large performance win we could make in {AppThemeBinding}.

17% of the time is spent just doing:

image

Which is inside here for {AppThemeBinding}:

https://github.com/dotnet/maui/blob/e0fa274fbdd5646d6f4bbf38cc74ed287b980869/src/Controls/src/Core/Application/Application.cs#L221-L225

Traces: collectionview.zip

mattleibow commented 10 months ago

We can have a look at making this not use an event and rather push the value to the controls. Sort of like how Window works because we only need to propagate if it changes.

mattleibow commented 10 months ago

After my PR, we got some data from @jonathanpeppers

This generally looks good, my Before:

image

vs After:

image

(NOTE just look at the % as the trace duration is not the same)

Traces taken while scrolling a sample on #18505: matthew.zip

mattleibow commented 10 months ago

This is crazy! Before, it was 45% just inflating (and all the bindings) items:

image

Inflation is still the top item, but now is only 8.6%!

image

mattleibow commented 10 months ago

My PR is building so if anyone has significant issues in their app and wan't to try it out: https://github.com/dotnet/maui/pull/19931

It is a bit of a scary change because it totally flips the order of the theme events, but it may be significant of a fix that makes this worth the scary things. If people try this out and we get some good feedback, then that will also help.

mikebikerider commented 9 months ago

I uploaded a sample MAUI CollectionView app to https://github.com/mikebikerider/CollectionViewSample-net8/tree/master . I wrote the app to explore why MAUI CollectionView pereforms so poorly compared to Xamarin.Forms, especially when a CollectionView resides inside a ScrollView. The sample has two pages. On the first page vertical scroll CollectionView is in a star row of the main grid. The second page vertical scroll CollectionView is inside horizontal scroll ScrollView that is in the star row of the main grid. The stand-alone CollectionView has no issues under either iOS or Android. Second page CollectionView inside the horizontal ScrollView performance, especially on Android, was horrible until I figured out that .net 8 ScrollView incorretly handles the size of hosted controls on iOS and Android. Not just hosted CollectionView. Grids are affected too, a 'star' column is handled as 'auto'. I eventually made it working by correcting the size of the CollectionView (vertical size on Android) or the size of the grid holding the CollectionView and its header (iOS). Tricks that should not be required. ScrollView hosted controls sizing issues under iOS are most noticeable on iPhones with a notch or dynamic island. It seems ScrollView does not take into account safe area insets in both portrait and landscape orientations, and I did not observe that under .net 7. On Android if I don't correct CollectionView vertical size when ItemsSource assigned and OnSizeAllocated() (screen rotated), scrolling more than couple of hundred items is not feasible. After size correction - 20000+. It is an awkward workaround, not a solution.

anpin commented 8 months ago

@mikebikerider the link you posted seems to be private

mikebikerider commented 8 months ago

I changed the repository to public. Thank you for pointing it out.