项目有这样的需求,

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

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

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

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

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

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

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

所以还需要一个list容器.

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

内部的核心流程,

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

2.异步发生此请求,

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

撤销的核心流程是.

1.让处理线程停止

2.取消队列中的任务,

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

  1. using System;

  1. using System.Windows;

  1. using System.Windows.Media.Imaging;

  1. using Proj.Interface;

  1.  

  1. namespace Proj.Common

  1. {

  1. /// <summary>

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

  1. /// </summary>

  1. public class HttpPicGet : IRevocable

  1. {

  1. public event GetPicCallback OnImageLoadCompleted;

  1. public event Action ProcessCompleted;

  1.  

  1. /// <summary>

  1. /// 当前正在处理的URL

  1. /// </summary>

  1. public string Url;

  1.  

  1. HttpResourceGet m_httpGet;

  1. public HttpPicGet()

  1. {

  1. m_httpGet = new HttpResourceGet();

  1. m_httpGet.OnDataStreamGenerated += (stream =>

  1. {

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

  1. {

  1. BitmapSource bi = new BitmapImage();

  1. bi.SetSource(stream);

  1. if (OnImageLoadCompleted != null)

  1. {

  1. OnImageLoadCompleted(bi);

  1. }

  1. });

  1. });

  1. m_httpGet.ProcessCompleted += (() =>

  1. {

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

  1. // {

  1. if (ProcessCompleted != null)

  1. {

  1. ProcessCompleted();

  1. }

  1. //});

  1. });

  1. }

  1.  

  1. public void BeginLoadPic(string url)

  1. {

  1. Url = url;

  1. m_httpGet.BeginGetData(url);

  1. }

  1.  

  1. public void RevokeAsync()

  1. {

  1. m_httpGet.RevokeAsync();

  1. }

  1. }

  1. }

  1. using System;

  1. using System.IO;

  1. using System.Net;

  1. using System.Windows.Media.Imaging;

  1. using Proj.Interface;

  1.  

  1. namespace Proj.Common

  1. {

  1. /// <summary>

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

  1. /// </summary>

  1. public delegate void GetDataStreamCallback(Stream stream);

  1.  

  1. /// <summary>

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

  1. /// </summary>

  1. public delegate void GetPicCallback(BitmapSource bimage);

  1.  

  1. /// <summary>

  1. /// 获取网络数据

  1. /// </summary>

  1. public class HttpResourceGet : IRevocable

  1. {

  1. public event GetDataStreamCallback OnDataStreamGenerated;

  1. public event Action ProcessCompleted;

  1. WebClient m_client;

  1. public HttpResourceGet()

  1. {

  1. m_client = new WebClient();

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

  1. {

  1. do

  1. {

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

  1. {

  1. break;

  1. }

  1. if (OnDataStreamGenerated != null)

  1. {

  1. OnDataStreamGenerated(ev.Result);

  1. //ev.Result.Close();

  1. }

  1. } while (false);

  1.  

  1. if (ProcessCompleted != null)

  1. {

  1. ProcessCompleted();

  1. }

  1. });

  1. }

  1.  

  1. public void BeginGetData(string url)

  1. {

  1. if (url.Contains("?"))

  1. {

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

  1. }

  1. else

  1. {

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

  1. }

  1.  

  1. m_client.OpenReadAsync(new Uri(url));

  1. }

  1.  

  1. public void RevokeAsync()

  1. {

  1. m_client.CancelAsync();

  1. }

  1. }

  1.  

  1. }

  1. using System.ComponentModel;

  1. using System.Windows.Media.Imaging;

  1.  

  1. namespace Proj.Common

  1. {

  1. public class MyImage : INotifyPropertyChanged

  1. {

  1.  

  1. public event PropertyChangedEventHandler PropertyChanged;

  1. string m_url;

  1. BitmapSource m_source;

  1.  

  1. public string URL

  1. {

  1. get { return m_url; }

  1. set

  1. {

  1. if (m_url != value)

  1. {

  1. m_url = value;

  1. OnPropertyChanged(new PropertyChangedEventArgs("URL"));

  1. }

  1. }

  1. }

  1.  

  1. public BitmapSource Source

  1. {

  1. get { return m_source; }

  1. set

  1. {

  1. if (m_source != value)

  1. {

  1. m_source = value;

  1. OnPropertyChanged(new PropertyChangedEventArgs("Source"));

  1. }

  1. }

  1. }

  1.  

  1. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)

  1. {

  1. if (PropertyChanged != null)

  1. PropertyChanged(this, args);

  1. }

  1. }

  1. }

  1. using System.Collections.Generic;

  1. using System.ComponentModel;

  1. using System.Threading;

  1. using Proj.Interface;

  1.  

  1. namespace Proj.Common

  1. {

  1. /// <summary>

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

  1. /// </summary>

  1. public class RevocableContainer

  1. {

  1. private class QueueItem

  1. {

  1. public GetPicCallback action;

  1. public string url;

  1. }

  1.  

  1. const int Threshold =3;

  1.  

  1. AutoResetEvent m_event;

  1. int m_count;

  1. bool m_isThreadProcessing;

  1. Queue<QueueItem> m_queue;

  1. List<IRevocable> m_list;

  1. object m_lock;

  1. public RevocableContainer()

  1. {

  1. m_event = new AutoResetEvent(false);

  1. m_queue = new Queue<QueueItem>();

  1. m_list = new List<IRevocable>();

  1. m_lock = new object();

  1. m_count = Threshold;

  1. m_isThreadProcessing = false;

  1. }

  1.  

  1. void HttpRequestThread()

  1. {

  1. while (true)

  1. {

  1. if (m_count == 0)

  1. {

  1. m_event.WaitOne();

  1. }

  1. QueueItem item = null;

  1. //out from queue

  1. lock (m_queue)

  1. {

  1. if (!m_isThreadProcessing)

  1. {

  1. break;

  1. }

  1. if (m_queue.Count == 0)

  1. {

  1. break;

  1. }

  1.  

  1. item = m_queue.Dequeue();

  1. Interlocked.Decrement(ref m_count);

  1.  

  1. }

  1.  

  1. //do request

  1. HttpPicGet pic = new HttpPicGet();

  1. pic.OnImageLoadCompleted += (img =>

  1. {

  1. item.action(img);

  1. });

  1.  

  1. pic.ProcessCompleted += (() =>

  1. {

  1. lock (m_list)

  1. {

  1. m_list.Remove(pic);

  1. }

  1. if (m_count == 0)

  1. {

  1. m_event.Set();

  1. }

  1. Interlocked.Increment(ref m_count);

  1. });

  1. pic.BeginLoadPic(item.url);

  1.  

  1. //into list

  1. lock (m_list)

  1. {

  1. m_list.Add(pic);

  1. }

  1.  

  1. Thread.Sleep(1);

  1. }

  1. }

  1.  

  1.  

  1. public void EnQueue(string url, GetPicCallback action)

  1. {

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

  1. BackgroundWorker worker = null;

  1. lock (m_queue)

  1. {

  1. m_queue.Enqueue(item);

  1. if (!m_isThreadProcessing)

  1. {

  1. m_isThreadProcessing = true;

  1. worker = new BackgroundWorker();

  1. }

  1. }

  1.  

  1. if (worker != null)

  1. {

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

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

  1. {

  1. lock (m_queue)

  1. {

  1. m_isThreadProcessing = false;

  1. }

  1. });

  1.  

  1. worker.RunWorkerAsync();

  1. }

  1.  

  1. }

  1.  

  1. /// <summary>

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

  1. /// </summary>

  1. public List<string> CancelAll()

  1. {

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

  1. lock (m_queue)

  1. {

  1. m_isThreadProcessing = false;

  1. foreach (var queueItem in m_queue)

  1. {

  1. unFinishedUrls.Add(queueItem.url);

  1. }

  1.  

  1. m_queue.Clear();

  1. }

  1. lock (m_list)

  1. {

  1. foreach (IRevocable item in m_list)

  1. {

  1. HttpPicGet picGet = (HttpPicGet)item;

  1. unFinishedUrls.Add(picGet.Url);

  1.  

  1. item.RevokeAsync();

  1. }

  1. }

  1.  

  1. return unFinishedUrls;

  1. }

  1. }

  1. }

界面层:

  1. using System.Collections.Generic;

  1. using System.Linq;

  1. using System.Windows;

  1. using Proj.Common;

  1. using Microsoft.Phone.Controls;

  1.  

  1. namespace Proj

  1. {

  1. public partial class PageImgTest : PhoneApplicationPage

  1. {

  1. RevocableContainer m_container = new RevocableContainer();

  1.  

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

  1.  

  1. object objLockunFinishUrls = new object();

  1.  

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

  1. {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. };

  1.  

  1. // Constructor

  1. public PageImgTest()

  1. {

  1. InitializeComponent();

  1. }

  1.  

  1. private void DoClick(object sender, RoutedEventArgs e)

  1. {

  1. _isInit = false;

  1.  

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

  1. StartLoad(sources);

  1. }

  1.  

  1. private void RevokeClick(object sender, RoutedEventArgs e)

  1. {

  1. if (_isProcessing) return;

  1.  

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

  1.  

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

  1.  

  1. if (lst.Count > 0)

  1. {

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

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

  1.  

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

  1. _unFinishUrls.AddRange(addlst);

  1. }

  1. else

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

  1.  

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

  1. }

  1.  

  1. private void BtnRetry_OnClick(object sender, RoutedEventArgs e)

  1. {

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

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

  1.  

  1. if (_isProcessing) return;

  1.  

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

  1. StartLoad(_unFinishUrls);

  1.  

  1. }

  1.  

  1. private bool _isInit = false;

  1. private bool _isProcessing = false;

  1.  

  1. /// <summary>

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

  1. /// </summary>

  1. void StartLoad(List<string> argImgUrls)

  1. {

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

  1.  

  1. if (_isProcessing) return;

  1. _isProcessing = true;

  1.  

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

  1.  

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

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

  1. //{

  1. // MyImage imgItem = new MyImage();

  1. // imgs.Add(imgItem);

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

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

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

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

  1. //}

  1.  

  1. if (!_isInit)

  1. {

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

  1. {

  1. ImageObj imgItem = new ImageObj();

  1. imgs.Add(imgItem);

  1. imgItem.URL = sources[i];

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

  1. {

  1. imgItem.Source = bitsource;

  1.  

  1. if (_unFinishUrls.Contains(imgItem.URL))

  1. _unFinishUrls.Remove(imgItem.URL);

  1. }));

  1. }

  1.  

  1. lbContent.DataContext = imgs;

  1. }

  1. else

  1. {

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

  1. {

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

  1.  

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

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

  1. {

  1. m_container.EnQueue(item, (bitsource =>

  1. {

  1. myImg.Source = bitsource;

  1.  

  1. if (_unFinishUrls.Contains(myImg.URL))

  1. _unFinishUrls.Remove(myImg.URL);

  1. }));

  1. }

  1. }

  1. }

  1.  

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

  1. {

  1. _isInit = true;

  1. }

  1.  

  1. _isProcessing = false;

  1. UpdateLayout();

  1.  

  1. }

  1.  

  1. }

  1. }

 
 
 
 
  1. <phone:PhoneApplicationPage

  1. x:Class="Proj.PageImgTest"

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

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

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

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

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

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

  1. FontFamily="{StaticResource PhoneFontFamilyNormal}"

  1. FontSize="{StaticResource PhoneFontSizeNormal}"

  1. Foreground="{StaticResource PhoneForegroundBrush}"

  1. SupportedOrientations="Portrait" Orientation="Portrait"

  1. mc:Ignorable="d"

  1. shell:SystemTray.IsVisible="True">

  1.  

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

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

  1. <Grid.RowDefinitions>

  1. <RowDefinition Height="Auto"/>

  1. <RowDefinition Height="*"/>

  1. </Grid.RowDefinitions>

  1.  

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

  1. <ListBox.ItemTemplate>

  1. <DataTemplate>

  1. <StackPanel Orientation="Horizontal">

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

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

  1. </StackPanel>

  1. </DataTemplate>

  1. </ListBox.ItemTemplate>

  1. </ListBox>

  1.  

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

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

  1. <StackPanel Orientation="Horizontal">

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

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

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

  1. </StackPanel>

  1. </Grid>

  1. </Grid>

  1.  

  1. </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. BIP_开发案例04_通过BI Publisher实现打印报表的二维码(案例)(待整理)

    2014-01-01 Created BaoXinjian

  2. Educational Codeforces Round 15 Cellular Network

    Cellular Network 题意: 给n个城市,m个加油站,要让m个加油站都覆盖n个城市,求最小的加油范围r是多少. 题解: 枚举每个城市,二分查找最近的加油站,每次更新答案即可,注意二分的时候 ...

  3. redis 数据持久化

    1.快照(snapshots) 缺省情况情况下,Redis把数据快照存放在磁盘上的二进制文件中,文件名为dump.rdb.你可以配置Redis的持久化策略,例如数据集中每N秒钟有超过M次更新,就将数据 ...

  4. fiddle 中 显示serverIp

    1.快捷键Ctrl+R  或者  菜单->Rules->Customize Rules 2.在CustomRules.js文件里Ctrl+F查找字符串 static function Ma ...

  5. FileSystemWatcher

    转:http://www.cnblogs.com/zhaojingjing/archive/2011/01/21/1941586.html 注意:用FileWatcher的Created监控文件时,是 ...

  6. 30天轻松学习javaweb_https协议的密码学

    https通过非对称加密实现数据安全1.CA机构提供数字证书,其中数字证书包含公钥.2.浏览器自带功能验证数字证书是否是CA机构颁发的.3.根据数字证书包含的公钥对表单数据进行加密.4.公钥提供方再根 ...

  7. SyntaxError: Non-UTF-8 code starting with '\xba' in file 错误的解决方法!!

    第一次在Eclipse建立python工程,添加了自己新建的文件,写了一点代码,随后执行时候出现了错误,和昨天我在Visual Studio 2015里面一样,错误: SyntaxError: Non ...

  8. NPM使用

    安装路径修改: 4.配置npm的全局模块存放路径和cache路径 输入以下命令 npm config set prefix  “D:\Program Files\node\node-global” n ...

  9. java程序内存使用

    一.内存使用示意图 二.java运行时数据区域 1.程序计数器: 当前线程所执行字节码的行号提示器. 2.java虚拟机栈: 线程私有,与线程生命周期相同,保存基本数据类型,如果线程所请求的栈深度大于 ...

  10. [Flex] ButtonBar系列——arrowKeysWrapFocus属性如果为 true,则使用箭头键在组件内导航时,如果击中某一端则将折回。

    <?xml version="1.0" encoding="utf-8"?> <!--arrowKeysWrapFocus 如果为 true, ...