项目有这样的需求,

要求窗口加载一揽子图片,为了不让UI阻塞太久,采用异步读取后绑定显示的方案.

图片的下载应该采用并发的过程(等待网络响应会很耗时,一张一张的下载,等待时间太长)

图片的下载不能占用过多的线程数,应有个阀值(图片不是核心业务,不能占用那么多资源)

在图片加载的过程中,如果用户有操作,比如窗口跳转,则未加载完成的图片加载的过程应取消(为了替用户节省流量).

需求就是这么多了,如何实现呢?

思路是这样的,由于需要异步,且需要等待,首先想到使用队列,先让队列排列起来,再定量迭代读取.

因为要涉及异步的取消,想到了用WebClient对象的异步功能, 当然,所以发起异步请求之后的对象我都需要记录,

所以还需要一个list容器.

外部接口是两个参数,url,图片的网址,一个回调,定义了图片下载完成后的操作.

内部的核心流程,

1.将一个图片任务从队列中取出,

2.异步发生此请求,

3.将发起请求的对象放进容器,以备撤销时使用.

撤销的核心流程是.

1.让处理线程停止

2.取消队列中的任务,

3.让等待响应的任务取消.

using System;

using System.Windows;

using System.Windows.Media.Imaging;

using Proj.Interface;

 

namespace Proj.Common

{

    /// <summary>

    /// 把网络数据包装为图片源

    /// </summary>

    public class HttpPicGet : IRevocable

    {

        public event GetPicCallback OnImageLoadCompleted;

        public event Action ProcessCompleted;

 

        /// <summary>

        /// 当前正在处理的URL

        /// </summary>

        public string Url;

 

        HttpResourceGet m_httpGet;

        public HttpPicGet()

        {

            m_httpGet = new HttpResourceGet();

            m_httpGet.OnDataStreamGenerated += (stream =>

            {

                Deployment.Current.Dispatcher.BeginInvoke(() =>

                {

                    BitmapSource bi = new BitmapImage();

                    bi.SetSource(stream);

                    if (OnImageLoadCompleted != null)

                    {

                        OnImageLoadCompleted(bi);

                    }

                });

            });

            m_httpGet.ProcessCompleted += (() =>

            {

                //Deployment.Current.Dispatcher.BeginInvoke(() =>

                // {

                     if (ProcessCompleted != null)

                     {

                         ProcessCompleted();

                     }

                 //});

            });

        }

 

        public void BeginLoadPic(string url)

        {

            Url = url;

            m_httpGet.BeginGetData(url);

        }

 

        public void RevokeAsync()

        {

            m_httpGet.RevokeAsync();

        }

    }

}

using System;

using System.IO;

using System.Net;

using System.Windows.Media.Imaging;

using Proj.Interface;

 

namespace Proj.Common

{

    /// <summary>

    /// 从网络读取流的回调

    /// </summary>

    public delegate void GetDataStreamCallback(Stream stream);

 

    /// <summary>

    /// 生成了图片源之后的回调

    /// </summary>

    public delegate void GetPicCallback(BitmapSource bimage);

 

    /// <summary>

    /// 获取网络数据

    /// </summary>

    public class HttpResourceGet : IRevocable

    {

        public event GetDataStreamCallback OnDataStreamGenerated;

        public event Action ProcessCompleted;

        WebClient m_client;

 

        public HttpResourceGet()

        {

            m_client = new WebClient();

            m_client.OpenReadCompleted += ((send, ev) =>

            {

                do

                {

                    if (ev.Error != null || ev.Cancelled)

                    {

                        break;

                    }

                    if (OnDataStreamGenerated != null)

                    {

                        OnDataStreamGenerated(ev.Result);

                        //ev.Result.Close();

                    }

                } while (false);

 

                if (ProcessCompleted != null)

                {

                    ProcessCompleted();

                }

            });

        }

 

        public void BeginGetData(string url)

        {

            if (url.Contains("?"))

            {

                url += "&rand=" + Guid.NewGuid();//加Guid保证调试时无缓存

            }

            else

            {

                url += "?rand=" + Guid.NewGuid();//加Guid保证调试时无缓存

            }

 

            m_client.OpenReadAsync(new Uri(url));

        }

 

        public void RevokeAsync()

        {

            m_client.CancelAsync();

        } 

    }

 

}

using System.ComponentModel;

using System.Windows.Media.Imaging;

 

namespace Proj.Common

{

    public class MyImage : INotifyPropertyChanged

    {

 

        public event PropertyChangedEventHandler PropertyChanged;

        string m_url;

        BitmapSource m_source;

 

        public string URL

        {

            get { return m_url; }

            set

            {

                if (m_url != value)

                {

                    m_url = value;

                    OnPropertyChanged(new PropertyChangedEventArgs("URL"));

                }

            }

        }

 

        public BitmapSource Source

        {

            get { return m_source; }

            set

            {

                if (m_source != value)

                {

                    m_source = value;

                    OnPropertyChanged(new PropertyChangedEventArgs("Source"));

                }

            }

        }

 

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)

        {

            if (PropertyChanged != null)

                PropertyChanged(this, args);

        }

    }

}

using System.Collections.Generic;

using System.ComponentModel; 

using System.Threading; 

using Proj.Interface;

 

namespace Proj.Common

{

    /// <summary>

    /// 容器,用来处理多条任务

    /// </summary>

    public class RevocableContainer

    {

        private class QueueItem

        {

            public GetPicCallback action;

            public string url;

        }

 

        const int Threshold =3;

 

        AutoResetEvent m_event;

        int m_count;

        bool m_isThreadProcessing;

        Queue<QueueItem> m_queue;

        List<IRevocable> m_list;

        object m_lock;

        public RevocableContainer()

        {

            m_event = new AutoResetEvent(false);

            m_queue = new Queue<QueueItem>();

            m_list = new List<IRevocable>();

            m_lock = new object();

            m_count = Threshold;

            m_isThreadProcessing = false;

        }

 

        void HttpRequestThread()

        {

            while (true)

            {

                if (m_count == 0)

                {

                    m_event.WaitOne();

                }

                QueueItem item = null;

                //out from queue

                lock (m_queue)

                {

                    if (!m_isThreadProcessing)

                    {

                        break;

                    }

                    if (m_queue.Count == 0)

                    {

                        break;

                    }

 

                    item = m_queue.Dequeue();

                    Interlocked.Decrement(ref  m_count);

 

                }

 

                //do request

                HttpPicGet pic = new HttpPicGet();

                pic.OnImageLoadCompleted += (img =>

                {

                    item.action(img);

                });

 

                pic.ProcessCompleted += (() =>

                {

                    lock (m_list)

                    {

                        m_list.Remove(pic);

                    }

                    if (m_count == 0)

                    {

                        m_event.Set();

                    }

                    Interlocked.Increment(ref m_count);

                });

                pic.BeginLoadPic(item.url);

 

                //into list

                lock (m_list)

                {

                    m_list.Add(pic);

                }

 

                Thread.Sleep(1);

            }

        }

 

 

        public void EnQueue(string url, GetPicCallback action)

        {

            QueueItem item = new QueueItem() { action = action, url = url };

            BackgroundWorker worker = null;

            lock (m_queue)

            {

                m_queue.Enqueue(item);

                if (!m_isThreadProcessing)

                {

                    m_isThreadProcessing = true;

                    worker = new BackgroundWorker();

                }

            }

 

            if (worker != null)

            {

                worker.DoWork += ((send, ev) => HttpRequestThread());

                worker.RunWorkerCompleted += ((send, ev) =>

                {

                    lock (m_queue)

                    {

                        m_isThreadProcessing = false;

                    }

                });

 

                worker.RunWorkerAsync();

            }

 

        }

 

        /// <summary>

        /// 取消全部,并返回未完成的(正在进行的及未开始的)

        /// </summary>

        public List<string> CancelAll()

        {

            List<string> unFinishedUrls=new List<string>();

            lock (m_queue)

            {

                m_isThreadProcessing = false;

                

             

                

                    foreach (var queueItem in m_queue)

                    {

                        unFinishedUrls.Add(queueItem.url);

                    }

                

 

                m_queue.Clear();

            }

            lock (m_list)

            {

                foreach (IRevocable item in m_list)

                {

                    HttpPicGet picGet = (HttpPicGet)item;

                    unFinishedUrls.Add(picGet.Url);

 

                    item.RevokeAsync();

                }

            }

 

            return unFinishedUrls;

        }

    }

}

界面层:

using System.Collections.Generic;

using System.Linq; 

using System.Windows;

using Proj.Common;

using Microsoft.Phone.Controls;

 

namespace Proj

{

    public partial class PageImgTest : PhoneApplicationPage

    {

        RevocableContainer m_container = new RevocableContainer();

 

        List<string> _unFinishUrls = new List<string>();

 

        object objLockunFinishUrls = new object();

 

        List<string> sources = new List<string>()

            {

                //"http://gb.cri.cn/mmsource/images/2008/05/26/ei080526395.jpg",

                //"http://gb.cri.cn/mmsource/images/2008/05/26/ei080526396.jpg",

                //"http://gb.cri.cn/mmsource/images/2008/05/26/ei080526397.jpg",

                //"http://gb.cri.cn/mmsource/images/2008/05/26/ei080526398.jpg",

                //"http://gb.cri.cn/mmsource/images/2008/05/26/ei080526399.jpg",

                //"http://gb.cri.cn/mmsource/images/2008/05/26/ei080526400.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526401.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526402.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526403.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526404.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526405.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526406.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526407.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526408.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526409.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526410.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526411.jpg",

                "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526412.jpg"

            };

 

        // Constructor

        public PageImgTest()

        {

            InitializeComponent();

        }

 

        private void DoClick(object sender, RoutedEventArgs e)

        {

            _isInit = false;

 

            MessageBox.Show("开始重新加载全部");

            StartLoad(sources);

        }

 

        private void RevokeClick(object sender, RoutedEventArgs e)

        {

            if (_isProcessing) return;

 

            List<string> lst = m_container.CancelAll();

 

            MessageBox.Show("取消数:" + lst.Count);

 

            if (lst.Count > 0)

            {

                var removelst = (from c in lst where _unFinishUrls.Contains(c) select c).ToList();

                _unFinishUrls.RemoveAll((a) => { return removelst.Contains(a); });

 

                var addlst = (from c in lst where !_unFinishUrls.Contains(c) select c).ToList();

                _unFinishUrls.AddRange(addlst);

            }

            else

                lst = _unFinishUrls.TakeWhile((a) => { return true; }).ToList();

 

            MessageBox.Show("未完成数:" + lst.Count);

        }

 

        private void BtnRetry_OnClick(object sender, RoutedEventArgs e)

        {

            if (!_isInit || lbContent.Items.Count == 0) return;

            //将未完成的图片继续加载

 

            if (_isProcessing) return;

 

            MessageBox.Show("开始处理的图片个数:" + _unFinishUrls.Count);

            StartLoad(_unFinishUrls);

 

        }

 

        private bool _isInit = false;

        private bool _isProcessing = false;

 

        /// <summary>

        /// 加载/继续加载未完成的

        /// </summary> 

        void StartLoad(List<string> argImgUrls)

        {

            if (argImgUrls == null || argImgUrls.Count == 0) return;

 

            if (_isProcessing) return;

            _isProcessing = true;

 

            List<ImageObj> imgs = new List<ImageObj>();

 

            //MyImage[] imgs = new MyImage[sources.Count]; 

            //for (int i = 0; i < argImgUrls.Count; ++i)

            //{

            //    MyImage imgItem = new MyImage();

            //    imgs.Add(imgItem);

            //    //imgs[i] = new MyImage();

            //    //MyImage imgItem = imgs[i];

            //    imgItem.URL = sources[i] + "?rand=" + Guid.NewGuid().ToString();//加Guid保证调试时无缓存

            //    m_container.EnQueue(imgItem.URL, (bitsource => imgItem.Source = bitsource));

            //}

 

            if (!_isInit)

            {

                for (int i = 0; i < argImgUrls.Count; ++i)

                {

                    ImageObj imgItem = new ImageObj();

                    imgs.Add(imgItem);

                    imgItem.URL = sources[i];

                    m_container.EnQueue(imgItem.URL, (bitsource =>

                    {

                        imgItem.Source = bitsource;

 

                        if (_unFinishUrls.Contains(imgItem.URL))

                            _unFinishUrls.Remove(imgItem.URL);

                    }));

                }

 

                lbContent.DataContext = imgs;

            }

            else

            {

                for (int i = 0; i < lbContent.Items.Count; i++)

                {

                    ImageObj myImg = (ImageObj)lbContent.Items[i];

 

                    var item = (from c in argImgUrls where c == myImg.URL select c).FirstOrDefault();

                    if (!string.IsNullOrEmpty(item))//匹配上

                    {

                        m_container.EnQueue(item, (bitsource =>

                        {

                            myImg.Source = bitsource;

 

                            if (_unFinishUrls.Contains(myImg.URL))

                                _unFinishUrls.Remove(myImg.URL);

                        }));

                    }

                }

            }

 

            if (!_isInit && imgs.Count > 0)

            {

                _isInit = true;

            }

 

            _isProcessing = false;

            UpdateLayout();

 

        }

 

    }

}

 
 
 
 
<phone:PhoneApplicationPage

    x:Class="Proj.PageImgTest"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"

    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    FontFamily="{StaticResource PhoneFontFamilyNormal}"

    FontSize="{StaticResource PhoneFontSizeNormal}"

    Foreground="{StaticResource PhoneForegroundBrush}"

    SupportedOrientations="Portrait" Orientation="Portrait"

    mc:Ignorable="d"

    shell:SystemTray.IsVisible="True">

 

    <!--LayoutRoot is the root grid where all page content is placed-->

    <Grid x:Name="LayoutRoot" Background="Transparent">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

 

        <ListBox Height="670" x:Name="lbContent" Grid.Row="0" ItemsSource="{Binding}">

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <StackPanel Orientation="Horizontal">

                        <Image Height="100" Width="100" Source="{Binding Source, Mode=OneWay}" />

                        <TextBlock Text="{Binding URL}" />

                    </StackPanel>

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

 

        <!--ContentPanel - place additional content here-->

        <Grid x:Name="ContentPanel" Grid.Row="1" VerticalAlignment="Bottom" Margin="12,0,12,0">

            <StackPanel Orientation="Horizontal">

                <Button x:Name="btnDo" Width="100" Height="100" Content="DO" Click="DoClick" />

                <Button x:Name="btnRevoke" Width="100" Height="100" Content="Revoke" Click="RevokeClick"  />

                <Button x:Name="btnRetry" Width="120" Height="100" Content="Retry" Click="BtnRetry_OnClick" />

            </StackPanel>

        </Grid>

    </Grid>

 

</phone:PhoneApplicationPage>

参考地址:http://blog.csdn.net/antsnm/article/details/6738292

WP_图片管理机制/异步读取网络图片的更多相关文章

  1. Android 利用 AsyncTask 异步读取网络图片

    1.新建Android工程AsyncLoadPicture 新建布局文件activity_main.xml主界面为一个GridView,还有其子项布局文件gridview_item.xml 2.功能主 ...

  2. tensorflow1.0 队列FIFOQueue管理实现异步读取训练

    import tensorflow as tf #模拟异步子线程 存入样本, 主线程 读取样本 # 1. 定义一个队列,1000 Q = tf.FIFOQueue(1000,tf.float32) # ...

  3. wemall app商城源码中基于JAVA的Android异步加载图片管理器代码

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  4. Android图片管理组件(双缓存+异步加载)

    转自:http://www.oschina.net/code/snippet_219356_18887?p=3#comments ImageManager2这个类具有异步从网络下载图片,从sd读取本地 ...

  5. WP_从独立存储区读取缓存的图片

      ///<summary> /// 独立存储缓存的图片源 /// 用法:item.img = new StorageCachedImage(newUri(http://www.baidu ...

  6. IOS- 内存管理机制

    iOS平台内存常见问题 作为iOS平台的开发者,是否曾经为内存问题而苦恼过?内存莫名的持续增长,程序莫名的crash,难以发现 的内存泄漏,这些都是iOS平台内存相关的常见问题:本文将会详细介绍iOS ...

  7. Linux 内核的文件 Cache 管理机制介绍

    Linux 内核的文件 Cache 管理机制介绍 http://www.ibm.com/developerworks/cn/linux/l-cache/ 1 前言 自从诞生以来,Linux 就被不断完 ...

  8. 分享一个安卓中异步获取网络图片并自适应大小的第三方程序(来自github)

    安卓中获取网络图片,生成缓存 用安卓手机,因为手机流量的限制,所以我们在做应用时,要尽量为用户考虑,尽量少耗点用户的流量,而在应用中网络图片的显示无疑是消耗流量最大的,所以我们可以采取压缩图片或者将图 ...

  9. java静态类、静态方法、静态代码块,静态变量及实例方法,实例变量初始化顺序及内存管理,机制

    1.当一个类被第一次使用时,它需要被类加载器加载,而加载过程涉及以下两点: (1)在加载一个类时,如果它的父类还未被加载,那么其父类必须先被加载: (2)当类加载到内存之后,按照在代码中的出现顺序执行 ...

随机推荐

  1. PLSQL_性能优化系列18_Oracle Explain Plan解析计划通过Baseline绑定

    2015-05-28 Created By BaoXinjian

  2. poj 2104 K-th Number(主席树 视频)

    K-th Number 题意: 给你一些数,让你求一个区间内,第k大的数是多少. 题解: 主席树第一题,看的qsc视频写的,戳戳戳 学到了unique函数,他的作用是:把相邻的重复的放到后面,返回值是 ...

  3. ylbtech-dbs:ylbtech-PurpleBill(票据管理系统)

    ylbtech-dbs:ylbtech-PurpleBill(票据管理系统) -- =============================================-- DatabaseNa ...

  4. JAVA 处理程序异常,(try、catch、finally),(thorws)

    一.try语句: try{//这里写可能出现异常的程序} catch(Exception e){//这里写如果出现异常怎么处理的程序} 二.throws语句 语法:函数方法()  throws Exc ...

  5. jQuery图片延迟加载插件jQuery.lazyload

      插件描述:jQuery图片延迟加载插件jQuery.lazyload,使用延迟加载在可提高网页下载速度.在某些情况下,它也能帮助减轻服务器负载. 使用方法 引用jquery和jquery.lazy ...

  6. CentOS yum安装和配置MySQL(转载)

    From:http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html] 一.MySQL简介 说到数据库,我们大多想到 ...

  7. iOS8远程通知处理

    // IOS8 新系统需要使用新的代码注册推送if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){    [[UI ...

  8. [经验总结]利用xlstproc处理XSLT的makefile

    转自:http://blog.csdn.net/thinkhy/article/details/5343739 # For XSLT PARSE = xsltproc SRC = main.xml S ...

  9. 第一个jave程序-helloworld

    1.打开myeclipse,其中有个select a workspase的过程,即选择工作空间,这里需要更换空间,不要放C盘,防止项目越来越大占用C盘的空间 2.创建java工程 3.取工程名,填写自 ...

  10. Linux命令 find和mv的结合使用:查找文件,移动到某个目录

    显示前十个文件 [root@localhost smgpbi]# ls -1 | sort -u | head -10 1.首先查看文件个数,进入所在的文件 # find . -name " ...