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. jQuery插件:跨浏览器复制jQuery-zclip(转载)

    转载地址:http://www.cnblogs.com/linjiqin/p/3532451.html jQuery-zclip是一个复制内容到剪贴板的jQuery插件,使用它我们不用考虑不同浏览器和 ...

  2. Arch Linux Installation Guide

    Arch Linux Installation Guide   timedatectl set-ntp true   sed -i '/Score/{/China/!{n;s/^/#/}}' /etc ...

  3. C# 使用Conditional特性而不是#if条件编译

    概述 #if/#endif 语句常用来基于同一份源码生成不同的编译结果,其中最常见的就是debug版和release版.但是这些工具在实际应用中并不是非常友好,因为它们容易被滥用,其代码页进而难以理解 ...

  4. sql语句中----删除表数据的"三兄弟"

    说到删除表数据的关键字,大家记得最多的可能就是delete了 然而我们做数据库开发,读取数据库数据.对另外的两兄弟用得就比较少了 现在来介绍另外两个兄弟,都是删除表数据的,其实也是很容易理解的 老大- ...

  5. Vijos P1459 车展 treap求任意区间中位数

    描述 遥控车是在是太漂亮了,韵韵的好朋友都想来参观,所以游乐园决定举办m次车展.车库里共有n辆车,从左到右依次编号为1,2,…,n,每辆车都有一个展台.刚开始每个展台都有一个唯一的高度h[i].主管已 ...

  6. loj 1377 (bfs)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1377 思路:这道题只要处理好遇到"*"这种情况就可以搞定了.我们可 ...

  7. 智能车学习(十六)——CCD学习

    一.使用硬件 1.兰宙CCD四代      优点:可以调节运放来改变放大倍数      缺点:使用软排线(容易坏),CCD容易起灰,需要多次调节   2.野火K60底层     二.CCD硬件电路 ( ...

  8. LoadRunner参数化之数据取值和更新方式

    其实看LR已经很久了,每次看到参数化的取值更新时,都没有看透,了解个大概就为止了,也确实挺搞脑子的. 现在理解下来 分成2部分 取值方式  Select next row 如何从数据列表中取值 Seq ...

  9. Spring中属性文件properties的读取与使用

    实际项目中,通常将一些可配置的定制信息放到属性文件中(如数据库连接信息,邮件发送配置信息等),便于统一配置管理.例中将需配置的属性信息放在属性文件/WEB-INF/configInfo.propert ...

  10. Android开发中Handler的经典总结

    当应用程序启动时,Android首先会开启一个主线程(也就是UI线程),主线程为管理界面中的UI控件,进行事件分发. AD: 一.Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线 ...