[WP8.1UI控件编程]Windows Phone大数据量网络图片列表的异步加载和内存优化
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大数据量网络图片列表的异步加载和内存优化的更多相关文章
- [WP8.1UI控件编程]Windows Phone VirtualizingStackPanel、ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件
11.2.2 VirtualizingStackPanel.ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件 VirtualizingStackPanel.ItemsSta ...
- [WP8.1UI控件编程]Windows Phone动画方案的选择
8.1 动画方案的选择 Windows Phone的动画实现方式有线性插值动画(3种类型).关键祯动画(4种类型)和基于帧动画,甚至还有定时器动画,然后动画所改变的UI元素属性可以是普通的UI元素属性 ...
- [WP8.1UI控件编程]Windows Phone理解和运用ItemTemplate、ContentTemplate和DataTemplate
2.2.5 ItemTemplate.ContentTemplate和DataTemplate 在理解ItemTemplate.ContentTemplate和DataTemplate的关系的之前,我 ...
- [WP8.1UI控件编程]Windows Phone XAML页面的编译
1.1.2 XAML页面的编译 Windows Phone的应用程序项目会通过Visual Studio完成XAML页面的编译,在程序运行时会通过直接链接操作加载和解析XAML,将XAML和过程式代码 ...
- [WP8.1UI控件编程]Windows Phone自定义布局规则
3.2 自定义布局规则 上一节介绍了Windows Phone的系统布局面板和布局系统的相关原理,那么系统的布局面板并不一定会满足所有的你想要实现的布局规律,如果有一些特殊的布局规律,系统的布局面板是 ...
- [WP8.1UI控件编程]SemanticZoom控件实现分组列表
11.1.5 SemanticZoom实现分组列表 SemanticZoom控件可以让用户实现一种更加高级的列表,这种列表可以对列表的项目进行分组,同时这个SemanticZoom控件会提供两个具有相 ...
- 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架
<深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...
- 大数据量时 Mysql LIMIT如何正确对其进行优化(转载)
以下的文章主要是对Mysql LIMIT简单介绍,我们大家都知道LIMIT子句一般是用来限制SELECT语句返回的实际行数.LIMIT取1个或是2个数字参数,如果给定的是2个参数,第一个指定要返回的第 ...
- zList一个块状链表算法可以申请和释放同种对象指针,对于大数据量比直接new少需要差不多一半内存
zList是一个C++的块状内存链表,特点: 1.对于某种类别需要申请大量指针,zList是一个很好的帮手,它能比new少很多内存. 2.它对内存进行整体管理,可以将数据和文件快速互操作 3.和vec ...
随机推荐
- Genymotion刷入谷歌应用市场以及获取root权限
Genymotion刷入谷歌应用市场以及获取root权限 - 推酷http://www.tuicool.com/articles/rEV3aa6 刷入gapp, arm框架,supersu的包要注意, ...
- 【翻译六】java-连接和实例
Joins The join method allows one thread to wait for the completion of another. If t is a Thread obje ...
- BI 项目管理之角色和职责
DW/BI 系统在生命周期中需要许多不同的角色和技能,它们来自业务和技术领域.本文将介绍创建DW/BI 系统所涉及的主要角色.角色和人之间很少是一对一关系.与我们合作的团队小到只有一人,大 ...
- DB2 日期相减
简单方法: 使用 days 字符型的日期:2012-01-01,2012-01-11 values days(date('2012-01-11')) - days(date('2012-01-01' ...
- Oracle备份 还原命令
1.备份命令 exp username/password file=d:/test/test.dmp; 2.还原命令 imp username/password full=y file=d:/test ...
- supervisor使用
supervisor是一个C/S系统,它可以在类unix操作系统让用户来监视和控制后台服务进程的数量,一个很重要的功能就是监控服务器的主要后台进程,并在出现问题是自动重启. 根据服务器上的python ...
- wpf 双击行。。获得行信息
void mydataGird_MouseDoubleClick(object sender, MouseButtonEventArgs e) { Point aP = e.GetPosition(m ...
- 汇编学习(五)——表处理程序
(一)串操作指令及重复前缀 一.串操作指令: 1.串传送指令: (1)指令格式: MOVS dst,rsc MOVSB ;ES:[DI]<--DS:[SI],SI<-SI+/-,DI< ...
- 智能车学习(十五)——K60野火2013版例程
一.中断函数注册方法: 1.格式: 配置某个功能的中断 注册中断函数 开启中断 2.一个例子 pit_init_ms(PIT0,);//定时中断初始化 set_vector_handler(PIT0_ ...
- SQLServer 表结构相关查询(快速了解数据库)
-- 表结构查询 SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, 字段序号 = a.colord ...