• 淘宝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;
      }
    }
  • 相关阅读:
    Java之lambda表达式
    修改IntelliJ IDEA的java编译版本
    no route to host解决方案、Failed to start LSB: Bring up/down networking的问题解决方案
    spark转换集合为RDD
    spark编写word count
    nexus
    spark 源码安装
    spark shell
    maven
    git
  • 原文地址:https://www.cnblogs.com/ms-uap/p/5072658.html
Copyright © 2020-2023  润新知