2015-11-05 42 views
1

我正在使用MvvmCross在Xamarin的Windows Phone應用程序上工作。在這個應用程序中,用戶從他的手機中選擇一些圖像。他們會顯示在列表中,然後用戶會對他們做任何事情。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}"/> 
顯示它們

沒什麼特別的。 我使用的測試圖像總大小爲34 MB。 使用VS中的性能和診斷工具,我可以確定應用程序在開始時的內存使用量約爲16 Mb。當我將測試圖像加載到應用程序時,它最高可達58 MB。就好像它仍然使用全尺寸的圖像。和(只是爲了測試),當我把decodepixelheight和寬度離開它飆升到約350 MB。我完全不知道爲什麼它會爲圖像使用如此多的內存。

因爲應用程序必須能夠使用更多更大的圖像,所以我需要找到一種方法來減少內存使用量。有誰知道我如何做到這一點?

回答

2

當你的照片被壓縮時,你的照片使用34 MB的存儲。要顯示,他們需要解壓縮。位圖圖片每個像素使用4個字節(每個顏色通道一個字節,RGB,加上alpha通道一個字節)。 因此,一張5百萬像素的圖片將使用大約20 MB的RAM。這就是爲什麼儘可能經常使用DecodePixelHeight/DecodePixelHeight是至關重要的原因。

仍然,有時候,你有來操縱巨大的圖片(如Lumia 1020的38 MP圖片,每個150 MB的RAM!)。爲此,諾基亞發佈了Imaging SDK(現在由Microsoft維護),允許您處理部分圖片,而不必將全部內容加載到內存中。

在你的情況下,主要問題是你一次加載所有的縮略圖,即使只有其中幾個將同時顯示。如果您想減少使用的內存量,則必須延遲加載縮略圖(即僅在需要時)。一種方法是存儲文件位置而不是BitmapImage,並根據需要加載圖片。不幸的是,你不能直接綁定到Image控件的路徑(除非文件在應用程序的本地存儲中)。 In that question,我建議爲有類似問題的人使用自定義用戶控件。

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; 
      } 
     } 
    } 
} 
+0

謝謝你的回答。我現在已經找到了解決方案。雖然這不是你向我展示的內容,但是你從另一個帖子給我的鏈接有解決方案。使用file.getScaledImageAsThumbnailAsync它會使用更少的內存(不知道爲什麼)。雖然將來我的應用程序還需要顯示整個圖片庫,因此我將查看您在那裏展示的ISupportIncrementalLoading。再次感謝您的幫助 – StijnvanGaal