XAML Extreme memory usage with .Net Maui CollectionView

nxowjjhe  于 12个月前  发布在  .NET
关注(0)|答案(1)|浏览(122)

我写了一个小工具来下载一个电台播放列表让我浏览,非常小而简单,而且很好用。但由于某种原因,对于略高于1k的项目(小于3Mb ob数据),该应用程序需要几乎1.4Gb的RAM。因此,要么是我没有看到内存泄漏,要么是我以不应该的方式使用了集合视图,要么是其他地方有bug(例如。在MAUI本身)。
我的应用程序是一个新的MAUI项目在VS中,只有MainPage文件被修改,我不想把这个小代码分散在多个文件上。代码如下:
MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Ö3_Playlist"
             x:Class="Ö3_Playlist.MainPage">

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">

            <Button
                x:Name="CounterBtn"
                Text="Parse"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />

            <ActivityIndicator IsVisible="{Binding IsBusy}" Color="White"/>

            <CollectionView ItemsSource="{Binding Entries}">
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="local:SongEntry">
                        <HorizontalStackLayout HorizontalOptions="FillAndExpand">
                            <Button Text="Open" Command="{Binding OpenCommand}"/>
                            <Entry Text="{Binding Name}" IsReadOnly="True"/>
                            <Button Text="{Binding IsLiked}" Command="{Binding ClickedCommand}"/>
                        </HorizontalStackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
            
        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

MainPage.cs

public partial class SongEntry : ObservableObject
    {
        [BsonId]
        public string Name { get; set; }

        [ObservableProperty]
        public int isLiked;

        [RelayCommand]
        private void Clicked()
        {
            if (isLiked == 0) IsLiked = 1;
            else if (isLiked == 1) IsLiked = -1;
            else IsLiked = 0;
            Database.Save(this);
        }

        [RelayCommand]
        private async void Open()
        {
            string uri = @"https://www.youtube.com/results?search_query=" + Name;
            await BrowserOpen_Clicked(uri);
        }

        private async Task BrowserOpen_Clicked(string url)
        {
            try
            {
                Uri uri = new Uri(url);
                await Browser.Default.OpenAsync(uri, BrowserLaunchMode.SystemPreferred);
            }
            catch (Exception ex)
            {
                // An unexpected error occurred. No browser may be installed on the device.
            }
        }
    }

    public class WebLoader
    {
        public IConfiguration AngleSharpConfiguration { get; set; }
        public IBrowsingContext AngleSharpContext { get; set; }

        public WebLoader()
        {
            AngleSharpConfiguration = Configuration.Default.WithDefaultLoader();
            AngleSharpContext = BrowsingContext.New(AngleSharpConfiguration);
        }

        public virtual async Task<IDocument> LoadWebpage(string url, int retries = 10)
        {
            IDocument document;
            int counter = 0;
            do
            {
                document = await AngleSharpContext.OpenAsync(url);
                counter++;
            } while (document == null || (document?.Body.ChildElementCount == 0 && counter < retries));

            return document;
        }

    }

    public class Database
    {
        static string dbFile = @"C:\SomePath\dbFile.db";

        public static IList<SongEntry> GetSongs()
        {
            IList<SongEntry> songs;
            using (var db = new LiteDatabase(dbFile))
            {
                songs = db.GetCollection<SongEntry>("Entries").FindAll().ToList<SongEntry>();
            }

            return songs;
        }

        public static void Save(IList<SongEntry> entries)
        {
            using (var db = new LiteDatabase(dbFile))
            {
                foreach(var e in entries)
                db.GetCollection<SongEntry>("Entries").Upsert(e);
            }
        }
        public static void Save(SongEntry entry)
        {
            using (var db = new LiteDatabase(dbFile))
            {
                db.GetCollection<SongEntry>("Entries").Upsert(entry);
            }
        }
        public static void Insert(SongEntry entry)
        {
            using (var db = new LiteDatabase(dbFile))
            {
                db.GetCollection<SongEntry>("Entries").Insert(entry);
            }
        }

    }

    public partial class ViewModel : ObservableObject
    {
        string dbFile = @"C:\Users\Thorsten\Desktop\Ö3_Playlist_Review.db";

        [ObservableProperty]
        IList<SongEntry> entries = new List<SongEntry>();

        [ObservableProperty]
        bool isBusy = false;

        public ViewModel()
        {
            Entries = Database.GetSongs();
        }
        ~ViewModel()
        {
            Database.Save(Entries);
        }

        public async Task Parse()
        {
            IsBusy = true;
            var loader = new WebLoader();

            for (int i = 0; i < 10; i++)
            {
                var doc = await loader.LoadWebpage(@"https://onlineradiobox.com/at/hitradiooe3/playlist/" + i);
                var list = GetSongs(doc);
                foreach (var song in list)
                {
                    if (Entries.FirstOrDefault(x => x.Name.Trim().ToLower() == song.Name.Trim().ToLower()) == null)
                    {
                        Database.Insert(song);
                        Entries.Add(song);
                    }
                }
            }
            IsBusy = false;

        }

        private IList<SongEntry> GetSongs(IDocument doc)
        {
            IList<SongEntry> list = new List<SongEntry>();

            var tmp = doc.Body.GetElementsByClassName("track_history_item");
            foreach (var item in tmp)
            {
                string name = item.Text().Trim();
                var s = new SongEntry() { Name = name };
                list.Add(s);
            }

            return list;
        }

    }

    public partial class MainPage : ContentPage
    {
        public ViewModel vm { get; set; } = new ViewModel();

        public MainPage()
        {
            BindingContext = vm;
            InitializeComponent();
        }

        private async void OnCounterClicked(object sender, EventArgs e)
        {
            await vm.Parse();
        }

    }

有人能看出问题吗?

zf9nrax1

zf9nrax11#

我相信你不能把CollectionView放在ScrollView中,因为它最终会一次呈现所有内容,而不是使用虚拟滚动。

相关问题