如何解决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;
}
}
有两点需要解释:
- 使用
BitmapImage
替换Image
,因为Image
是一个控件,我们可以在ListView.ItemTemplate
中创建它 - 将
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)。加载完成后,内存使用量将大大下降。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。