Windows Phone图像的高内存使用率
本文关键字:内存 使用率 高内存 Phone 图像 Windows | 更新日期: 2023-09-27 18:20:45
我正在Xamarin中使用MvvmCross开发Windows Phone应用程序。在这个应用程序中,用户从他的手机中选择一些图像。它们被显示在一个列表中,然后用户对它们进行处理。
我使用FileOpenPicker进行文件选择,并从这些文件中创建BitmapImages以显示
foreach (StorageFile file in args.Files) {
BitmapImage thumbnail = new BitmapImage();
thumbnail.DecodePixelType = DecodePixelType.Physical;
try {
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) {
thumbnail.DecodePixelHeight = 70;
thumbnail.DecodePixelWidth = 70;
thumbnail.SetSource(fileStream);
fileStream.Dispose();
}
}
catch (OutOfMemoryException e) {
Mvx.Trace("MEMORY IS FULL");
}
在一些其他代码之后,我把这些BitmapImages放在ObservableCollection中,并像一样显示它们
<Image Style="{StaticResource imageListImage}" Source="{Binding Thumbnail}"/>
没什么特别的。我使用的测试图像的总大小为34MB。使用VS i的性能和诊断工具,我能够确定应用程序在启动时的内存使用量约为16Mb。当我将测试图像加载到应用程序中时,它的大小达到了58MB。就好像它仍然使用了图像的全尺寸一样。(只是为了测试)当我去掉decodepixel的高度和宽度时,它飙升到了大约350 MB。我完全不知道为什么它要用这么多内存来处理图像。
因为应用程序必须能够使用更多更大的图像,我需要找到一种方法来减少内存使用。有人知道我该怎么做吗?
压缩图片时,图片将使用34MB的存储空间。要显示,需要对它们进行解压缩。位图图片每像素使用4个字节(每个颜色通道RGB一个字节,alpha通道一个字节)因此,一张500万像素的图片将使用大约20 MB的RAM这就是为什么尽可能频繁地使用DecodePixelHeight
/DecodePixelHeight
至关重要。
尽管如此,有时,您必须操作巨大的图片(例如Lumia 1020的3800万张图片,每张图片有150 MB的RAM!!)。为此,诺基亚发布了Imaging SDK(现在由微软维护),允许您处理部分图片,而不必将全部内容加载到内存中。
在您的情况下,主要问题是您一次加载所有缩略图,即使只有少数缩略图会同时显示。如果你想减少使用的内存量,你必须延迟加载缩略图(也就是说,只有在需要的时候)。一种方法是存储文件位置而不是BitmapImage
,并根据需要加载图片。不幸的是,您无法直接将路径绑定到Image
控件(除非文件在应用程序的本地存储中)。在这个问题中,我建议为有类似问题的人使用自定义用户控件。
public sealed partial class LocalImage : UserControl
{
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof (string),
typeof (LocalImage), new PropertyMetadata(null, SourceChanged));
public LocalImage()
{
this.InitializeComponent();
}
public string Source
{
get { return this.GetValue(SourceProperty) as string; }
set { this.SetValue(SourceProperty, value); }
}
private async static void SourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var control = (LocalImage)obj;
var path = e.NewValue as string;
if (string.IsNullOrEmpty(path))
{
control.Image.Source = null;
}
else
{
var file = await StorageFile.GetFileFromPathAsync(path);
using (var fileStream = await file.OpenAsync(FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
control.Image.Source = bitmapImage;
}
}
}
}