淘寶UWP--自定義圖片緩存


一、應用場景

在淘寶應用首頁,會有很多張圖片,而這些首頁圖片不會經常改變,所以就需要緩存下來。這樣就不必每次都從網絡獲取。

二、比較對象

1.系統緩存

對於系統緩存,我們不需要做什么處理。只需要把網絡圖片的URL賦值給Image控件就行了。這樣系統就會在每次需要用到圖片的時候,有限查找緩存里有沒有之前下載好的。

2.自建緩存區域

自建緩存不給Image控件賦URL,而是把圖片DownLoad下來,生成一個bitmap,然后把bitmap賦值給Image。同時將這個bitmap存儲下來。當下次要用到這幅圖的時候,就直接從存儲的位置找到這幅圖。

三、自建緩存方法

下邊這段代碼將uri[]數組中的圖片下載下來,然后通過WriteToFile()函數將圖片保存到本地,同時,記下存儲的文件名。

SoftwareBitmap sb = await DownloadImage(uri[i]);
if (sb != null)
{
  //sb = await ReadFromFile(fileName[i]);
  SoftwareBitmapSource source = new SoftwareBitmapSource();
  await source.SetBitmapAsync(sb);
  this.insideImage.Source = source;
  sb = await DownloadImage(uri[i]);
  fileName[i] = await WriteToFile(sb);
}


當你需要使用圖片的時候,使用下列代碼,通過ReadFromFile()函數將圖片讀取出來就行了。

for (int i = 0; i < 50; i++)
{
  
//SoftwareBitmap sb = await DownloadImage(uri[i]);   SoftwareBitmap sb = await ReadFromFile(fileName[i]);   SoftwareBitmapSource source = new SoftwareBitmapSource();
  await source.SetBitmapAsync(sb);   this.insideImage.Source = source;
  //source.Dispose(); }

 

四、效率對比

下邊我通過對比兩種緩存機制發現各有用武之地。

1.對於幾百K到幾兆的大圖片,系統緩存有速度優勢。

2.對於幾K到幾十K的小圖片,自建緩存區有速度優勢。

測試背景1:三張大圖片,循環33次(共99次)

圖片大小:338k 618k 1810k

 

PC測試

         

系統緩存(CPU周期)

3066584

3058505

3079367

3078989

3076976

自建緩存(CPU周期)

53669280

51842991

52839051

52078772

52305373

 

Phone測試

       

系統緩存(CPU周期)

31852799

32008575

32200748

31970601

31839003

自建緩存(CPU周期)

741909215

750950455

765863510

760865505

781048686

 

結論一:對於幾百K到幾兆的大圖片,系統緩存有速度優勢。

 

測試背景2:三張小圖片,循環33次(共99次)

圖片大小:3k 6k 60k

PC測試

系統緩存(CPU周期)

3057284

3057637

3080880

3063350

3059105

自建緩存(CPU周期)

1316247

1318369

1364584

1333684

1362956

 

Phone測試

系統緩存(CPU周期)

32085084

31751734

31744715

31852230

32064768

自建緩存(CPU周期)

27114317

26041012

26821794

27365796

30211258

 

結論二:對於幾K到幾十K的小圖片,自建緩存區有速度優勢。

 手機淘寶項目測試數據:

測試背景:50張小圖片,循環一次(共50次)

系統緩存

CPU周期

23689650

21589548

25409150

25186302

23121251

 

RAM

51

52

50

52

52

             
             

自建緩存

CPU周期

3186761

2892837

2963193

2942235

2741501

 

RAM

61

63

61

60

59

 PS:RAM占用是峰值,穩定后兩種方式RAM占用相同。

五、測試方法

通過給一個Image控件賦值,來看到效果。

1、系統緩存

系統緩存測試不能通過直接改變url的方式,因為系統緩存是異步的,他不會等一個圖片加載好再加載另一個圖,而是直接忽略了之前的改變。

private async void test1()
{
  stopwatch.Reset();
  stopwatch.Start();
  BitmapImage bi = new BitmapImage();
  bi.UriSource = new Uri(uri[0]);
  this.insideImage.Source = bi;
 } 

private void insideImage_ImageOpened(object sender, RoutedEventArgs e)
{
  times++;
  if (times == 50)
  {
    stopwatch.Stop();
    textBox.Text = "任務"+testnum.ToString()+"用時:" + stopwatch.ElapsedTicks + ".";
    return;
  }

  BitmapImage bi = new BitmapImage();
  bi.UriSource = new Uri(uri[times]);
  this.insideImage.Source = bi;
 } 

 2、自建緩存

private async void test2()
{
  stopwatch.Reset();
  stopwatch.Start();
  for (int i = 0; i < 50; i++)
  {
    //SoftwareBitmap sb = await DownloadImage(uri[i]);
    SoftwareBitmap sb = await ReadFromFile(fileName[i]);
    SoftwareBitmapSource source = new SoftwareBitmapSource();
    await source.SetBitmapAsync(sb);
    if (i % 3 == 0)
    {
      this.insideImage.Source = source;
    }
    else if (i % 3 == 1)     {       this.insideImage1.Source = source;     }
    else if (i % 3 == 2)     {       this.insideImage2.Source = source;     }     //source.Dispose();
  }   stopwatch.Stop();   textBox.Text = "任務" + testnum.ToString() + "用時:" + stopwatch.ElapsedTicks + "."; }

 

附:關鍵代碼代碼

ReadFromFile()函數通過文件名讀取圖片 ,特別注意這句話

SoftwareBitmapsoftwareBitmap = awaitdecoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);

 一定要加上編碼方式,不然會報錯。

public async Task<SoftwareBitmap> ReadFromFile(string filename)
{
  StorageFile file = await _localFolder.CreateFileAsync(filename, CreationCollisionOption.OpenIfExists);
  //var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri( filename));
  using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
  {
    // Create the decoder from the stream
    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
    // Get the SoftwareBitmap representation of the file
    SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
    return softwareBitmap;
  }
}

 WriteToFile()函數將bitmap寫入存儲區

public async Task<string> WriteToFile(SoftwareBitmap softwareBitmap)
{
  string fileName = Path.GetRandomFileName();

  if (softwareBitmap != null)
  {
    // save image file to cache
    StorageFile file = await _localFolder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
      BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
      encoder.SetSoftwareBitmap(softwareBitmap);
      await encoder.FlushAsync();
  }
}

  return fileName;
 } 

DownloadImage()函數通過url下載圖片,返回bitmap

private async Task<SoftwareBitmap> DownloadImage(string url)
{
  try
  {
    HttpClient hc = new HttpClient();
    HttpResponseMessage resp = await hc.GetAsync(new Uri(url));
    resp.EnsureSuccessStatusCode();
    IInputStream inputStream = await resp.Content.ReadAsInputStreamAsync();
    IRandomAccessStream memStream = new InMemoryRandomAccessStream();
    await RandomAccessStream.CopyAsync(inputStream, memStream);
    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(memStream);
    SoftwareBitmap softBmp = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
    return softBmp;
  }
  catch (Exception ex)
  {
    return null;
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM