淘宝UWP--自定义图片缓存

Cle****-he UID.1073626
2016-01-21 发表

本帖最后由 Clever-he 于 2016-1-21 10:48 编辑

一、应用场景

在淘宝应用首页,会有很多张图片,而这些首页图片不会经常改变,所以就需要缓存下来。这样就不必每次都从网络获取。

[align=center]***附件停止解析***[/align]

二、比较对象

1.系统缓存

对于系统缓存,我们不需要做什么处理。只需要把网络图片的URL赋值给Image控件就行了。这样系统就会在每次需要用到图片的时候,有限查找缓存里有没有之前下载好的。

2.自建缓存区域

自建缓存不给Image控件赋URL,而是把图片DownLoad下来,生成一个bitmap,然后把bitmap赋值给Image。同时将这个bitmap存储下来。当下次要用到这幅图的时候,就直接从存储的位置找到这幅图。

三、自建缓存方法

下边这段代码将uri[]数组中的图片下载下来,然后通过WriteToFile()函数将图片保存到本地,同时,记下存储的文件名。

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



当你需要使用图片的时候,使用下列代码,通过ReadFromFile()函数将图片读取出来就行了。

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


四、效率对比

下边我通过对比两种缓存机制发现各有用武之地。

1.对于几百K到几兆的大图片,系统缓存有速度优势。

2.对于几K到几十K的小图片,自建缓存区有速度优势。

测试背景1:三张大图片,循环33次(共99次)

图片大小:338k 618k 1810k

***附件停止解析***



***附件停止解析***


结论一:对于几百K到几兆的大图片,系统缓存有速度优势。



测试背景2:三张小图片,循环33次(共99次)

图片大小:3k 6k 60k

***附件停止解析***


***附件停止解析***


结论二:对于几K到几十K的小图片,自建缓存区有速度优势。


手机淘宝项目测试数据:

测试背景:50张小图片,循环一次(共50次)

***附件停止解析***

PS:RAM占用是峰值,稳定后两种方式RAM占用相同。


五、测试方法


通过给一个Image控件赋值,来看到效果。


1、系统缓存

系统缓存测试不能通过直接改变url的方式,因为系统缓存是异步的,他不会等一个图片加载好再加载另一个图,而是直接忽略了之前的改变。

[mw_shl_code=csharp,true]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;
}
[/mw_shl_code]


2、自建缓存

[mw_shl_code=csharp,true]private async void test2()
{
  stopwatch.Reset();
  stopwatch.Start();
  for (int i = 0; i < 50; i++)
  {
    //SoftwareBitmap sb = await DownloadImage(uri);
    SoftwareBitmap sb = await ReadFromFile(fileName);
    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 + ".";
}

[/mw_shl_code]


附:关键代码代码

ReadFromFile()函数通过文件名读取图片 ,特别注意这句话

[mw_shl_code=csharp,true]SoftwareBitmapsoftwareBitmap = awaitdecoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
[/mw_shl_code]

一定要加上编码方式,不然会报错。

[mw_shl_code=csharp,true]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;
  }
}


[/mw_shl_code]


WriteToFile()函数将bitmap写入存储区

[mw_shl_code=csharp,true]
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;
}
[/mw_shl_code]



DownloadImage()函数通过url下载图片,返回bitmap

[mw_shl_code=csharp,true]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;
  }
}

[/mw_shl_code]

开发者交流群:53078485,期待您的加入!

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
liu****521 UID.1019533
2016-01-21 回复

好高级的样子 可是我不懂

Cle****-he UID.1073626
2016-01-22 回复

Quote***链接停止解析***
好高级的样子 可是我不懂


那就加入我们的开发者交流群53078485吧,一起来交流和学习

Vincent唐龑 UID.1186913
2016-01-22 使用 Lumia 640 XL 回复

QuoteClever-he 发表于 2016-1-22 10:21
那就加入我们的开发者交流群53078485吧,一起来交流和学习


没有任何编程基础

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报