根据Stefan Wick的博客,从图像中释放内存就像在做:
BitmapImage bitmapImage = image.Source as BitmapImage;
bitmapImage.UriSource = null;
image.Source = null;
但是,如何在Xaml中使用数据绑定,如何实现相同的效果?:
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e) {
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages() {
List<string> links = ThisMethodGetsLinks();
Links.Clear();
foreach(var link in links)
Links.Add(link);
}
ObservableCollection<string> _links;
public ObservableCollection<string> Links {
get {
if (_links == null)
_links = new ObservableCollection<string>();
return _links;
}
}
在这种情况下,每个按钮点击会消耗额外的内存,直到手机/模拟器崩溃。尽管清除了Listbox的ItemSource属性,但图像不会从内存中释放。
答案 0 :(得分:2)
BitmapCreateOptions Enumeration因此定义了BackgroundCreation枚举:
使BitmapSource在声明后立即初始化。此选项将图像缓存用于以前使用的URI。如果图像不在图像缓存中,则将在单独的后台线程上下载和解码图像。
这让我觉得当您更改UriSource属性并处理旧图像时,不会通知处理位图下载的后台线程,并且后台线程会继续下载图像。这可能是因为手机实现了它自己对所有图像的缓存(注意BitmapCreateOptions枚举的“IgnoreImageCache”元素的存在)。
这可能是罪魁祸首,但另一种可能性是ListBox的虚拟化实际上并未发生。最常见的原因是列表中的项目未明确定义为具有相同的高度。 ListBox中的虚拟化使用了封面下的VirtualizingStackPanel,并要求每个项目都具有相同的高度。如果任何项目的高度不同,则会取消虚拟化行为。下面是一些代码,可以帮助您确定是否真的。实际上是否正在发生。虚拟化的另一个方面是,在下载图像数据之前,您的图像目前没有设置高度。这意味着在下载图像之前,所有图像的高度均为0像素。如果所有图像都具有0像素的高度,那么这意味着根据virt,它们都是“在视图中”。逻辑,他们都应该开始下载。
总之,试试这些:
包含图像数据的简单结构:
using System.Diagnostics;
public class BoundImage
{
private string imageURL;
public static int TotalImagesRequested = 0;
public BoundImage(string url)
{
imageURL = url;
}
public string ImageURL
{
get
{
TotalImagesRequested++;
// Watch the output window and see if TotalImagesRequested is
// growing to a crazy high amount (if it is it will eventually
// reach the total Count of the _links variable. But your
// app may crash before that happens.
Debug.WriteLine("Images being requested: " + TotalImagesRequested);
return imageURL;
}
}
}
公开链接的更改属性:
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages()
{
List<string> links = ThisMethodGetsLinks();
Links.Clear();
_links = new ObservableCollection<BoundImage>();
foreach(string link in links)
{
_links.Add(new BoundImage(link));
}
}
ObservableCollection<BoundImage> _links;
public ObservableCollection<BoundImage> Links
{
get
{
if (_links == null)
_links = new ObservableCollection<BoundImage>();
return _links;
}
set
{
_links = value;
}
}
将XAML更改为Hook绑定到BoundImage的ImageURL属性:
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>