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. .net学习之CTS、CLS和CLR

    CLR:公共语言运行时,就是所有.net语言写的程序的公共运行时环境,比如C#.VB.Net等语言写的程序需要运行在CLR上,然后CLR解析执行操作系统的相关指令,CLR是.net程序运行在操作系统的 ...

  2. 【JAVA集合框架之Set】

    一.Set概述. Set集合的特点是元素不允许重复,而且是无序的(添加和取出的顺序不一致). Set接口中的方法和Collection接口中的方法几乎相同,略. Set接口下常用的两个类:HashSe ...

  3. POJ1699 HDU 1560 Best Sequence(AC自动机 最短路)

    曾写过迭代加深搜索的方法,现在使用在AC自动上跑最短路的方法 dp[i][j]表示状态为到节点i,模式串是否包含的状态为j的最短串的长度,则状态转移方程为: dp[nx][ny] = min(dp[x ...

  4. HTML页面实现返回顶部效果 go to top

    1.首先导入jQuery插件. 2.js代码: $(window).scroll(function () { if($(window).scrollTop()>=100) { $(". ...

  5. NS 802.11函数分析(一)

    recv函数有两个作用,不仅是接收其他节点发送的包,而且当节点接收到其他包的时候也会调用recv() 首先给出NS2中recv的源码,和一些注释: void Mac802_11::recv(Packe ...

  6. 上四条只是我目前总结菜鸟们在学习FPGA时所最容易跑偏的地

    长期以来很多新入群的菜鸟们总 是在重复的问一些非常简单但是又让新手困惑不解的问题.作为管理员经常要给这些菜鸟们普及基础知识,但是非常不幸的是很多菜鸟怀着一种浮躁的心态来学习 FPGA,总是急于求成. ...

  7. [转]svn常用命令

    谢谢原作者:http://blog.sina.com.cn/s/blog_963453200101eiuq.html 1.检出svn  co  http://路径(目录或文件的全路径) [本地目录全路 ...

  8. 近实时运算的利器---presto在公司实践

    1.起因 公司hadoop集群里的datanonde和tasktracker节点负载主要集中于晚上到凌晨,平日工作时间负载不是很高.但在工作时间内,公司业务人员有实时查询需求,现在主要 借助于hive ...

  9. AJAX案例二:简单表单验证

    案例:如果用户名输入为张三,那么在失去焦点时后面会显示该用户名已被注册,否则显示可以注册! <%@ page language="java" import="jav ...

  10. jvm运行机制与内存管理

    http://blog.csdn.net/lengyuhong/article/details/5953544 http://www.cnblogs.com/nexiyi/p/java_memory_ ...