11.2.4 大数据量网络图片列表的异步加载和内存优化

虚拟化技术可以让Windows Phone上的大数据量列表不必担心会一次性加载所有的数据,保证了UI的流程性。对于虚拟化的技术,我们不仅仅只是依赖其来给列表加载数据,还可以利用虚拟化的特性去做更多的事情。虚拟化技术有一个很重要的特性就是,它可以准确地判断出哪些列表项处于手机屏幕中,可以动态地去更新这些数据。基于这样的特性,我们可以给列表的功能做更多的优化。

那么下面我们基于一个例子来讲解利用虚拟化技术去做列表的性能优化。有这么一个需求,需要实现一个图片的列表,图片都是来自网络的,然后数据集合也很大。做这个网络图片列表功能时会面临着两个问题,一个是图片的加载会比较耗时,两外一个是当不断地滑动会让数据集合加载的图片占用的内存会越来越高。

对于第一个问题,可以采用异步加载的方式来解决,这样列表加载完之后,图片再显示出来,列表首次加载的速度会很快。那么我们可以通过后台线程调用网络请求下载图片,下载完图片之后再触发UI线程把图片显示出来。

第二个问题是要解决内存的问题,那么可以使用弱引用类型(WeakReference类)来存储图片的数据。弱引用就是不保证不被垃圾回收器回收的对象,它拥有比较短暂的生命周期,在垃圾回收器扫描它所管辖的内存区域过程中,一旦发现了只具有弱引用的对象,就会回收它的内存,不过一般情况下,垃圾回收器的线程优先级很低,也就不会很快发现那些只有弱引用的对象。当内存的使用会影响到程序的流畅运行的时候,垃圾回收器,就会按照优先次序把存在时间长的弱引用对象回收,从而释放内存。所以弱引用特别适合在当前这种情况下,占用大量内存,但通过垃圾回收功能回收以后很容易重新创建的图片对象。图片下载完之后会存放在弱引用对象里面,当检查到数据被回收的时候,再进行异步加载,当然你也可以把图片用独立存储存起来,这样也就免去了再次请求网络的操作。

下面我们来实现网络图片列表的异步加载和内存优化的示例:

代码清单11-8网络图片列表(源代码:第11章\Examples_11_8)

(1)创建数据实体类Data类,在Data类里面封装异步加载图片和弱引用的逻辑。

Data.cs文件主要代码
------------------------------------------------------------------------------------------------------------------
// Data类从INotifyPropertyChanged派生,要实现绑定属性改变的事件,用于图片异步请求完成之后可以更新到UI上
public class Data: INotifyPropertyChanged
{
// 图片名字属性
public string Name { get; set; }
// 当前的页面对象,用于触发UI线程
public Page Page { get; set; }
// 图片的网络地址
private Uri imageUri;
public Uri ImageUri
{
get
{
return imageUri;
}
set
{
if (imageUri == value)
{
return;
}
imageUri = value;
bitmapImage = null;
}
}
// 若引用对象,用于存储下载好的图片对象
WeakReference bitmapImage;
// ImageSource属性用于绑定到列表的Image控件上
public ImageSource ImageSource
{
get
{
if (bitmapImage != null)
{
// 如果弱引用没有没回收,则取弱引用的值
if (bitmapImage.IsAlive)
return (ImageSource)bitmapImage.Target;
else
Debug.WriteLine("数据已经被回收");
}
// 弱引用已经被回收那么则通过图片网络地址进行异步下载
if (imageUri != null)
{
Task.Factory.StartNew(() =>{ DownloadImage(imageUri);});
}
return null;
}
}
// 下载图片的方法
void DownloadImage(object state)
{
HttpWebRequest request = WebRequest.CreateHttp(state as Uri);
request.BeginGetResponse(DownloadImageComplete, request);
}
// 完成图片下载的回调方法
async void DownloadImageComplete(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
// 读取网络的数据
Stream stream = response.GetResponseStream();
int length = int.Parse(response.Headers["Content-Length"]);
// 注意需要把数据流重新复制一份,否则会出现跨线程错误
// 网络下载到的图片数据流,属于后台线程的对象,不能在UI上使用
Stream streamForUI = new MemoryStream(length);
byte[] buffer = new byte[length];
int read=;
do
{
read = stream.Read(buffer, , length);
streamForUI.Write(buffer, , read);
} while (read == length);
streamForUI.Seek(, SeekOrigin.Begin);
// 触发UI线程处理位图和UI更新
await Page.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
BitmapImage bm = new BitmapImage();
bm.SetSource(streamForUI.AsRandomAccessStream());
// 把图片位图对象存放到若引用对象里面
if (bitmapImage == null)
bitmapImage = new WeakReference(bm);
else
bitmapImage.Target = bm; //触发UI绑定属性的改变
OnPropertyChanged("ImageSource");
}
);
}
// 属性改变事件
async void OnPropertyChanged(string property)
{
var hander = PropertyChanged;
if (hander != null)
await Page.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
hander(this, new PropertyChangedEventArgs(property));
});
}
public event PropertyChangedEventHandler PropertyChanged;
}

(2)使用ListView控件绑定到数据Data对象的数据集合。

MainPage.xaml文件主要代码
------------------------------------------------------------------------------------------------------------------
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" Height="80"></TextBlock>
<Image Source="{Binding ImageSource}" Width="200" Height="200"></Image>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MainPage.xaml.cs文件主要代码
------------------------------------------------------------------------------------------------------------------
public MainPage()
{
InitializeComponent();
// 创建一个有1000个Data对象的数据集合
List<Data> Items = new List<Data>();
for (int i = ; i < ; i++)
{
// 在网络地址后面加上index=i是为了保证每个网络地址的不一样
// 这样就不会产生网络数据缓存,更加接近真实的网络图片列表
Items.Add(new Data { Name = "Test" + i, Page = this, ImageUri = new Uri("http://pic002.cnblogs.com/images/2012/152755/2012120917494440.png?index=" + i) });
}
listView.ItemsSource=Items;
}

本文来源于《深入理解Windows Phone 8.1 UI控件编程》

源代码下载:http://vdisk.weibo.com/s/zt_pyrfNHoezI

欢迎关注我的微博@WP林政

WP8.1技术交流群:372552293

[WP8.1UI控件编程]Windows Phone大数据量网络图片列表的异步加载和内存优化的更多相关文章

  1. [WP8.1UI控件编程]Windows Phone VirtualizingStackPanel、ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件

    11.2.2 VirtualizingStackPanel.ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件 VirtualizingStackPanel.ItemsSta ...

  2. [WP8.1UI控件编程]Windows Phone动画方案的选择

    8.1 动画方案的选择 Windows Phone的动画实现方式有线性插值动画(3种类型).关键祯动画(4种类型)和基于帧动画,甚至还有定时器动画,然后动画所改变的UI元素属性可以是普通的UI元素属性 ...

  3. [WP8.1UI控件编程]Windows Phone理解和运用ItemTemplate、ContentTemplate和DataTemplate

    2.2.5 ItemTemplate.ContentTemplate和DataTemplate 在理解ItemTemplate.ContentTemplate和DataTemplate的关系的之前,我 ...

  4. [WP8.1UI控件编程]Windows Phone XAML页面的编译

    1.1.2 XAML页面的编译 Windows Phone的应用程序项目会通过Visual Studio完成XAML页面的编译,在程序运行时会通过直接链接操作加载和解析XAML,将XAML和过程式代码 ...

  5. [WP8.1UI控件编程]Windows Phone自定义布局规则

    3.2 自定义布局规则 上一节介绍了Windows Phone的系统布局面板和布局系统的相关原理,那么系统的布局面板并不一定会满足所有的你想要实现的布局规律,如果有一些特殊的布局规律,系统的布局面板是 ...

  6. [WP8.1UI控件编程]SemanticZoom控件实现分组列表

    11.1.5 SemanticZoom实现分组列表 SemanticZoom控件可以让用户实现一种更加高级的列表,这种列表可以对列表的项目进行分组,同时这个SemanticZoom控件会提供两个具有相 ...

  7. 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架

    <深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...

  8. 大数据量时 Mysql LIMIT如何正确对其进行优化(转载)

    以下的文章主要是对Mysql LIMIT简单介绍,我们大家都知道LIMIT子句一般是用来限制SELECT语句返回的实际行数.LIMIT取1个或是2个数字参数,如果给定的是2个参数,第一个指定要返回的第 ...

  9. zList一个块状链表算法可以申请和释放同种对象指针,对于大数据量比直接new少需要差不多一半内存

    zList是一个C++的块状内存链表,特点: 1.对于某种类别需要申请大量指针,zList是一个很好的帮手,它能比new少很多内存. 2.它对内存进行整体管理,可以将数据和文件快速互操作 3.和vec ...

随机推荐

  1. 与你相遇好幸运,Sails.js自定义responses

    在 /api/responses/ 新建文件 >serviceDBError.js 自定义的数据库错误 >serviceError.js  自定义的数据错误 >serviceSucc ...

  2. Linux内核驱动之GPIO子系统(一)GPIO的使用

    转自:http://blog.csdn.net/mirkerson/article/details/8464290 一 概述 Linux内核中gpio是最简单,最常用的资源(和 interrupt , ...

  3. Delphi面向对象的属性

    可以把属性看成是能对类中的数据进行修改和执行代码的特殊的辅助域.对于组件来说,属性就是列在Object Inspector窗口的内容.下面的例子定义了一个有属性的简单对象 TMyObject = cl ...

  4. 【译】Visual Studio 15 预览版更新说明

    序:恰逢Build2016大会召开,微软发布了VS2015的update2更新包和VS2016预览版.本人正在提升英文水平中,于是在这里对VS2016预览版的官方文档进行了部分翻译.因为VS有些功能使 ...

  5. C#DataGridView合计处理

    网上查了一些关于合计的代码 ,但发现大都都不尽人意,就自己再根据资料改了一下. #region 合计 //调用方法示例 //HeJi heji = null; //heji = new HeJi(la ...

  6. 豆瓣的账号登录及api操作

    .douban.php <?php /** * PHP Library for douban.com * * @author */ class doubanPHP { function __co ...

  7. hdu 2891 中国剩余定理

    从6点看到10点,硬是没算出来,早知道玩游戏去了,艹,明天继续看 不爽,起来再看,终于算是弄懂了,以后超过一个小时的题不会再看了,不是题目看不懂,是水平不够 #include<cstdio> ...

  8. [Eclipse] eclipse中打开xml文件,使用ctrl+鼠标左键无法跳转至Java源文件【待解决】

    eclipse中打开xml文件,使用ctrl+鼠标左键无法跳转至Java源文件: 1. 设置eclipse ctrl + 左键打开源文件代码,如下图,设置都正常 2. 在网上找了很多种办法,均失败,在 ...

  9. 程序员最喜爱的12个Android应用开发框架二(转)

    在上一篇程序员最喜爱的12个Android应用开发框架(一)中,我们为大家介绍了前6个Android应用开发框架,主要包括了 Xamarin.Phonegap.Corona SDK等.接下来,小编将继 ...

  10. Codeforces Round#250 D. The Child and Zoo(并差集)

    题目链接:http://codeforces.com/problemset/problem/437/D 思路:并差集应用,先对所有的边从大到小排序,然后枚举边的时候,如果某条边的两个顶点不在同一个集合 ...