开发者社区> 科技小能手> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

[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=0;            do
            {
                read = stream.Read(buffer, 0, length);
                streamForUI.Write(buffer, 0, read);
            } while (read == length);
            streamForUI.Seek(0, 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 = 0; i < 1000; 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



本文转自linzheng 51CTO博客,原文链接:http://blog.51cto.com/linzheng/1559361


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
[Windows Phone] 以多国语言做为开发前提 (2)
原文:[Windows Phone] 以多国语言做为开发前提 (2) ? 前言 在先前的文章 [Windows Phone 开发 - 以多国语言做为开发前提 (1)] 中说明了简单的多国语言范例,今天再补充两个常见的例子,讯息中包含变数和图片,方法一样是透过资源档的方式达成。
759 0
Windows Phone开发(39):漫谈关键帧动画上篇
原文: Windows Phone开发(39):漫谈关键帧动画上篇 尽管前面介绍的几种动画会让觉得很好玩了,但是,不知道你是否发现,在前面说到的一系列XXXAnimation中,都有一个共同点,那就是仅仅针对两个值的目标值之间产生动画,如果使用By,将在原值和加上By后的目标值之间进行动画处理;如果使用From,To,那就更好理解了,就是首尾两个值之间值的动画。
959 0
Windows Phone开发(31):画刷
原文: Windows Phone开发(31):画刷 画刷是啥玩意儿?哈,其实画刷是用来涂鸦,真的,没骗你,至于你信不信,反正我信了。 本文通过价绍几个典型的画刷,使你明白画刷就是用来涂鸦的。
754 0
Windows Phone开发(7):当好总舵主
原文: Windows Phone开发(7):当好总舵主 吹完了页面有关的话题,今天我们来聊一下页面之间是如何导航的,在更多情况下,我们的应用程序不会只有一个页面的,应该会有N个,就像我们做桌面应 用开发那样,我们一个应用程序中可能不止一个窗体(极简单的程序除外),我们要处理窗体之间的切换;同理地,在进行Web开发的时候,我们的Web应用程序可能也不止一个页面,我们要处理页面之间的切换。
761 0
Windows Phone开发(25):启动器与选择器之WebBrowserTask
原文: Windows Phone开发(25):启动器与选择器之WebBrowserTask 从名字上就看出来,这个家伙就是打开浏览并浏览到指定页面。 它有两个用途完全一样的属性:Uri属性是System.Uri类型,这是新写进的属性; URL是字符串类型,但如果使用该属性,会发出警告“已过时”,所以建议使用前者。
848 0
Windows Phone开发(18):变形金刚第九季——变换
原文: Windows Phone开发(18):变形金刚第九季——变换 变换不是一个好理解的概念,不是吓你,它涉及很多有关代数,几何,以及线性代数的知识。怎么?被我的话吓怕了?不用怕,尽管我们未必能够理解这些概念,只要我们知道怎么使用它们就是了。
831 0
Windows Phone开发(21):做一个简单的绘图板
原文: Windows Phone开发(21):做一个简单的绘图板 其实我们今天要说的就是一个控件——InkPresenter,这个控件并不是十分强大,没办法和WPF中的InkCanvas相比,估计在实际开发中也很少可能会用到它,不过,我们还是来了解一下吧,毕竟用起来也不难。
760 0
Windows Phone开发(17):URI映射
原文: Windows Phone开发(17):URI映射 前面在讲述导航的知识,也讲了控件,也讲了资源,样式,模板,相信大家对UI部分的内容应该有了很直观的认识了。
764 0
Windows Phone开发(2):竖立自信,初试锋茫
原文: Windows Phone开发(2):竖立自信,初试锋茫  上一篇文章中,我们聊了一些“大炮”话题,从这篇文章开始,我们一起来学习WP开发吧。   一、我们有哪些装备。
895 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
ECS运维指南之Windows系统诊断
立即下载
《云服务器运维之Windows篇》
立即下载
FIS Global Accelerating Digital Intelligence in FinTech
立即下载