微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Incrementalloading Collection会加载所有数据,并且不会释放内存

如何解决Incrementalloading Collection会加载所有数据,并且不会释放内存

我的ListView仅包含在其上呈现了pdf页面的图像控件。我正在通过一种方法获取每个页面,该方法通过一个简单的循环调用,只要剩下页面就可以了。由于pdf可能真的很大,由于渲染的页面数量我有时会遇到内存不足的异常。我阅读了有关Ui和数据虚拟化的文章,而UI虚拟化似乎可以正常工作,而我的数据虚拟化却没有。 我阅读了Incrementalloading集合并实现了该接口。在这个集合中,我添加了我从方法中获得的每张图像。我看到GetPagedItemsAsync方法在程序开始时仅被调用一次。

public class IncrementalLoadingCollection :  IIncrementalSource<Image>
{      
    Rendering u;
    public IncrementalLoadingCollection()
    {
      
    }
    public async Task<IEnumerable<Image>> GetPagedItemsAsync(int pageIndex,int pageSize,CancellationToken cancellationToken = default)
    {
        u = new Rendering();          
        var result = (from p in u.collection select p).Skip(pageIndex * pageSize).Take(pageSize);

        await Task.Delay(1000);
        
        return result;
    }       
}

渲染是我的课程,负责执行文档和单页的加载。 我将在下面提供一个代码片段,我想问一下:接口的实现是否错误或者是否有更严重的错误使数据无法增量加载?

在Rendering.cs中:

在构造函数中:

     public IncrementalLoadingCollection<IncrementalLoadingCollection,Image> collection = new IncrementalLoadingCollection<IncrementalLoadingCollection,Image>();

在loadDocument函数中:

for (uint i = 0; i <= l_document.PageCount - 1; i++)

{

                    Image img = await LoadPage(l_document,i);                   
                    collection.Add(img);
                    g_rootPage.ListViewControl.ItemsSource = collection;
                    

}

EDIT1:

我在Github上放了一个程序的小例子,其中包含了除异常处理之类的基本功能

https://github.com/ShionLightwood/PDFDemo

解决方法

我检查了您的项目,IIncrementalSource接口的实现可能存在一些问题。

PdfDocument可以根据页面索引加载页面。因此,增量加载意味着我们需要在页面滚动到底部时从PdfDocument的当前页面索引之后获取页面,而不是在开始时加载所有页面,然后使用Task.Delay强制延迟。

因此,我的建议是创建一个PdfSource类,其目的与原始IncrementalLoadingCollection(在项目中)相同,用于处理增量加载。但是不同之处在于,内置变量是PdfDocument的实例。

public class PdfSource : IIncrementalSource<BitmapImage>
{
    private PdfDocument _document;

    public PdfSource(PdfDocument doc)
    {
        _document = doc;
    }

    public async Task<IEnumerable<BitmapImage>> GetPagedItemsAsync(int pageIndex,int pageSize,CancellationToken cancellationToken = default)
    {
        List<BitmapImage> result = new List<BitmapImage>();
        int count = 0;
        if (pageIndex < _document.PageCount)
        {
            for (int i = pageIndex; i < _document.PageCount; i++)
            {
                count++;
                if (count == pageSize)
                    break;
                var bitmap = await GetPageAsync((uint)i);
                if (bitmap != null)
                    result.Add(bitmap);
            }
        }
        return result;
    }

    private async Task<BitmapImage> GetPageAsync(uint index)
    {
        var bitmap = new BitmapImage();
        PdfPage pdfPage;
        PdfPageRenderOptions option = new PdfPageRenderOptions();
        option.DestinationHeight = 1200;
        option.DestinationWidth = 1000;
        using (IRandomAccessStream Imagestream = new MemoryStream().AsRandomAccessStream())
        {
            try
            {
                using (pdfPage = _document.GetPage(index))
                {
                    await pdfPage.RenderToStreamAsync(Imagestream,option);
                    await bitmap.SetSourceAsync(Imagestream);
                    bitmap.DecodePixelHeight = 1200;
                    bitmap.DecodePixelWidth = 1000;
                }
                return bitmap;
            }
            catch (ArgumentException ex)
            {
                Windows.UI.Popups.MessageDialog accessDenial = new Windows.UI.Popups.MessageDialog(ex.Message);
                await accessDenial.ShowAsync();
            }
        }
        return default;
    }
}

有两点需要解释:

  1. 使用BitmapImage替换Image,因为Image是一个控件,我们可以在ListView.ItemTemplate中创建它
  2. option.DestinationHeight修改为合适的值,太大会影响加载速度。

在“渲染”类中,我们还需要进行修改。

class Rendering
{
    private MainPage g_rootPage;       
    PdfDocument l_document;
    public IncrementalLoadingCollection<PdfSource,BitmapImage> collection;

    public Rendering()
    {
        g_rootPage = MainPage.Current;
    }

    public async Task LoadDocument(string source)
    {
        StorageFile l_file;
        l_file = await StorageFile.GetFileFromPathAsync(source);
        l_document = await PdfDocument.LoadFromFileAsync(l_file);
        var pdfSource = new PdfSource(l_document);
        collection = new IncrementalLoadingCollection<PdfSource,BitmapImage>(pdfSource);
        g_rootPage.ListViewControl.ItemsSource = collection;
    }
}

MainPage.xaml

<ListView ...>
    <!-- other code -->
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="BitmapImage">
            <Image Source="{Binding}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

修改完成后,增量加载即可正常运行。也就是说,滚动到底部进行加载(您可以添加一些加载说明UI)。加载完成后,内存使用量将大大下降。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。