设为首页 收藏本站
查看: 1001|回复: 0

转 Windows Phone 7 图片缓存

[复制链接]

尚未签到

发表于 2015-5-12 08:03:21 | 显示全部楼层 |阅读模式
  LowProfileImageLoader 的思路是将图片的Uri都放入到一个队列中,然后依次遍历这个队列去请求图片资源,下载好后通知UI将流返回,每当有新UI插入进来后都会唤醒工作线程, 并且我们可以设置工作线程一次可以同时对几个Uri进行处理,默认是5个。
  理解了 LowProfileImageLoader 的思路后,我们依据 LowProfileImageLoader 定制一个简单的图片缓存,即如果我们已经下载过这张图片了,我们就把图片保存到本地,等到下次启动程序的时候,判断本地是否已经缓存过该图片,如果缓存过 该图片,就从本地读取图片返回;如果没有缓存过该图片,则下载完后通知UI,然后将图片保存至本地。
  在线程工作的主方法WorkerThreadProc中的请求网络之前增加判断,判断该图片是否缓存
  if (pendingRequest.Uri.IsAbsoluteUri)
  {
  //load from isolated storage if has been cached
  if (IsImageCached(pendingRequest.Uri))
  {
  if (null!=LoadCachedImage(pendingRequest.Uri))
  {
  pendingCompletions.Enqueue(new PendingCompletion(pendingRequest.Image, pendingRequest.Uri, LoadCachedImage(pendingRequest.Uri)));
  }
  }
  else
  {
  // Download from network
  var webRequest = HttpWebRequest.CreateHttp(pendingRequest.Uri);
  webRequest.AllowReadStreamBuffering = true; // Don't want to block this thread or the UI thread on network access
  webRequest.BeginGetResponse(HandleGetResponseResult, new ResponseState(webRequest, pendingRequest.Image, pendingRequest.Uri));
  }                       
  }
  如果已经缓存了,直接推入到完成队列中,也就是准备向UI回调了。
  在回调中增加处理,如果没有缓存的,需要将图片进行缓存
  // Decode the image and set the source
  var pendingCompletion = pendingCompletions.Dequeue();
  if (GetUriSource(pendingCompletion.Image) == pendingCompletion.Uri)
  {
  //if has been cached,do not cache
  if (!IsImageCached(pendingCompletion.Uri))
  {
  CacheImage(pendingCompletion.Stream, pendingCompletion.Uri);
  }
  try
  {
  ImageSource bitmap;
  var bitmapImage = new BitmapImage();
  bitmapImage.SetSource(pendingCompletion.Stream);
  bitmap = bitmapImage;
  pendingCompletion.Image.Source = bitmap;
  }
  catch(Exception ex)
  {
  // Ignore image decode exceptions (ex: invalid image)
  }
  }
  下面的方法是判断图片有没有缓存的
  private static bool IsImageCached(Uri u)
  {
  string filePath = Path.Combine(Constants.CACHE_DIR_IMAGES, GetParsePath(u.ToString()));
  using (var store=IsolatedStorageFile.GetUserStoreForApplication())
  {
  if (store.FileExists(filePath))
  {
  return true;
  }
  }
  return false;
  }
  其中涉及到将图片的uri解析的问题,因为一般图片的uri都是http://….jpg之类的,为了避免不必要的麻烦,需要将uri进行相应的转码:
  private static string GetParsePath(string url)
  {
  return url.Replace("://", "").Replace("/","_");
  }
  下面的方法是从缓存中读取图片流的
  private static Stream LoadCachedImage(Uri u)
  {
  string filePath = Path.Combine(Constants.CACHE_DIR_IMAGES, GetParsePath(u.ToString()));
  using (var store = IsolatedStorageFile.GetUserStoreForApplication())
  {
  if (!store.FileExists(filePath))
  {
  return null;
  }
  return store.OpenFile(filePath, FileMode.Open, FileAccess.Read);
  }
  }
  以及将图片缓存的方法:
  private static bool CacheImage(Stream source,Uri u)
  {
  string filePath = Path.Combine(Constants.CACHE_DIR_IMAGES, GetParsePath(u.ToString()));
  using (var store = IsolatedStorageFile.GetUserStoreForApplication())
  {
  try
  {
  if (!store.DirectoryExists(Constants.CACHE_DIR_IMAGES))
  {
  store.CreateDirectory(Constants.CACHE_DIR_IMAGES);
  }
  using (var stream = store.OpenFile(filePath, FileMode.OpenOrCreate, FileAccess.Write))
  {
  byte[] bytes = new byte[source.Length];
  source.Read(bytes, 0, (int)source.Length);
  stream.Write(bytes, 0, (int)source.Length);
  }
  return true;
  }
  catch (Exception)
  {
  return false;
  throw;
  }
  }
  }
  调用方法是这样的
  
  在XAML中的Image中添加如上的代码即可,这样只要图片一被下载,就会被缓存到本地,以便下次使用。
  当然你可以加上一个依赖属性,判断当前是否启动缓存。另外一个需要考虑的是,何时删除图片缓存,那由你的app决定!
  完整代码 :
  // Copyright (C) Microsoft Corporation. All Rights Reserved.
// This code released under the terms of the Microsoft Public License
// (Ms-PL, http://opensource.org/licenses/ms-pl.html).
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.IsolatedStorage;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Delay
{
    ///
    /// Provides access to the Image.UriSource attached property which allows
    /// Images to be loaded by Windows Phone with less impact to the UI thread.
    /// rewrite by alexis
    ///
    public static class LowProfileImageLoader
    {
        private const int WorkItemQuantum = 5;
        private static readonly Thread _thread = new Thread(WorkerThreadProc);
        private static readonly Queue _pendingRequests = new Queue();
        private static readonly Queue _pendingResponses = new Queue();
        private static readonly object _syncBlock = new object();
        private static bool _exiting;
        ///
        /// Gets the value of the Uri to use for providing the contents of the Image's Source property.
        ///
        /// Image needing its Source property set.
        /// Uri to use for providing the contents of the Source property.
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "UriSource is applicable only to Image elements.")]
        public static Uri GetUriSource(Image obj)
        {
            if (null == obj)
            {
                throw new ArgumentNullException("obj");
            }
            return (Uri)obj.GetValue(UriSourceProperty);
        }
        ///
        /// Sets the value of the Uri to use for providing the contents of the Image's Source property.
        ///
        /// Image needing its Source property set.
        /// Uri to use for providing the contents of the Source property.
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "UriSource is applicable only to Image elements.")]
        public static void SetUriSource(Image obj, Uri value)
        {
            if (null == obj)
            {
                throw new ArgumentNullException("obj");
            }
            obj.SetValue(UriSourceProperty, value);
        }
        ///
        /// Identifies the UriSource attached DependencyProperty.
        ///
        public static readonly DependencyProperty UriSourceProperty = DependencyProperty.RegisterAttached(
            "UriSource", typeof(Uri), typeof(LowProfileImageLoader), new PropertyMetadata(OnUriSourceChanged));
        ///
        /// Gets or sets a value indicating whether low-profile image loading is enabled.
        ///
        public static bool IsEnabled { get; set; }
        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Static constructor performs additional tasks.")]
        static LowProfileImageLoader()
        {
            // Start worker thread
            _thread.Start();
            Application.Current.Exit += new EventHandler(HandleApplicationExit);
            IsEnabled = true;
        }
        private static void HandleApplicationExit(object sender, EventArgs e)
        {
            // Tell worker thread to exit
            _exiting = true;
            if (Monitor.TryEnter(_syncBlock, 100))
            {
                Monitor.Pulse(_syncBlock);
                Monitor.Exit(_syncBlock);
            }
        }
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Relevant exceptions don't have a common base class.")]
        private static void WorkerThreadProc(object unused)
        {
            Queue pendingRequests = new Queue();
            Queue pendingResponses = new Queue();
            while (!_exiting)
            {
                lock (_syncBlock)
                {
                    // Wait for more work if there's nothing left to do
                    if ((0 == _pendingRequests.Count) && (0 == _pendingResponses.Count) && (0 == pendingRequests.Count) && (0 == pendingResponses.Count))
                    {
                        Monitor.Wait(_syncBlock);
                        if (_exiting)
                        {
                            return;
                        }
                    }
                    // Copy work items to private collections
                    while (0 < _pendingRequests.Count)
                    {
                        pendingRequests.Enqueue(_pendingRequests.Dequeue());
                    }
                    while (0 < _pendingResponses.Count)
                    {
                        pendingResponses.Enqueue(_pendingResponses.Dequeue());
                    }
                }
                Queue pendingCompletions = new Queue();
                // Process pending requests
                for (var i = 0; (i < pendingRequests.Count) && (i < WorkItemQuantum); i++)
                {
                    var pendingRequest = pendingRequests.Dequeue();
                    //AndreasHammar 2011-01-25: is getting this in the Tre.News app
                    if (pendingRequest.Uri == null) continue;
                    if (pendingRequest.Uri.IsAbsoluteUri)
                    {
                        //load from isolated storage if has been cached
                        if (IsImageCached(pendingRequest.Uri))
                        {
                            if (null!=LoadCachedImage(pendingRequest.Uri))
                            {
                                pendingCompletions.Enqueue(new PendingCompletion(pendingRequest.Image, pendingRequest.Uri, LoadCachedImage(pendingRequest.Uri)));
                            }
                        }
                        else
                        {
                            // Download from network
                            var webRequest = HttpWebRequest.CreateHttp(pendingRequest.Uri);
                            webRequest.AllowReadStreamBuffering = true; // Don't want to block this thread or the UI thread on network access
                            webRequest.BeginGetResponse(HandleGetResponseResult, new ResponseState(webRequest, pendingRequest.Image, pendingRequest.Uri));
                        }                        
                    }
                    else
                    {
                        // Load from application (must have "Build Action"="Content")
                        var originalUriString = pendingRequest.Uri.OriginalString;
                        // Trim leading '/' to avoid problems
                        var resourceStreamUri = originalUriString.StartsWith("/", StringComparison.Ordinal) ? new Uri(originalUriString.TrimStart('/'), UriKind.Relative) : pendingRequest.Uri;
                        // Enqueue resource stream for completion
                        var streamResourceInfo = Application.GetResourceStream(resourceStreamUri);
                        if (null != streamResourceInfo)
                        {
                            pendingCompletions.Enqueue(new PendingCompletion(pendingRequest.Image, pendingRequest.Uri, streamResourceInfo.Stream));
                        }
                    }
                    // Yield to UI thread
                    Thread.Sleep(1);
                }
                // Process pending responses
                for (var i = 0; (i < pendingResponses.Count) && (i < WorkItemQuantum); i++)
                {
                    var pendingResponse = pendingResponses.Dequeue();
                    var responseState = (ResponseState)pendingResponse.AsyncState;
                    try
                    {
                        var response = responseState.WebRequest.EndGetResponse(pendingResponse);
                        pendingCompletions.Enqueue(new PendingCompletion(responseState.Image, responseState.Uri, response.GetResponseStream()));
                    }
                    catch (WebException)
                    {
                        // Ignore web exceptions (ex: not found)
                    }
                    // Yield to UI thread
                    Thread.Sleep(1);
                }
                // Process pending completions
                if (0 < pendingCompletions.Count)
                {
                    // Get the Dispatcher and process everything that needs to happen on the UI thread in one batch
                    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        while (0 < pendingCompletions.Count)
                        {
                            // Decode the image and set the source
                            var pendingCompletion = pendingCompletions.Dequeue();
                            if (GetUriSource(pendingCompletion.Image) == pendingCompletion.Uri)
                            {
                                //if has been cached,do not cache
                                if (!IsImageCached(pendingCompletion.Uri))
                                {
                                    CacheImage(pendingCompletion.Stream, pendingCompletion.Uri);
                                }
                                try
                                {
                                    ImageSource bitmap;
                                    var bitmapImage = new BitmapImage();
                                    bitmapImage.SetSource(pendingCompletion.Stream);
                                    bitmap = bitmapImage;
                                    pendingCompletion.Image.Source = bitmap;
                                }
                                catch(Exception ex)
                                {
                                    // Ignore image decode exceptions (ex: invalid image)
                                }
                            }
                            else
                            {
                                // Uri mis-match; do nothing
                            }
                            // Dispose of response stream
                            pendingCompletion.Stream.Dispose();
                        }
                    });
                }
            }
        }
        private static string GetParsePath(string url)
        {
            return url.Replace("://", "").Replace("/","_");
        }
        private static bool IsImageCached(Uri u)
        {
            string filePath = Path.Combine("Images", GetParsePath(u.ToString()));
            using (var store=IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (store.FileExists(filePath))
                {
                    return true;
                }
            }
            return false;
        }
        private static Stream LoadCachedImage(Uri u)
        {
            string filePath = Path.Combine("Images", GetParsePath(u.ToString()));
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!store.FileExists(filePath))
                {
                    return null;
                }
                return store.OpenFile(filePath, FileMode.Open, FileAccess.Read);
            }
        }
        private static bool CacheImage(Stream source,Uri u)
        {
            string filePath = Path.Combine("Images", GetParsePath(u.ToString()));
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                try
                {
                    if (!store.DirectoryExists("Images"))
                    {
                        store.CreateDirectory("Images");
                    }
                    using (var stream = store.OpenFile(filePath, FileMode.OpenOrCreate, FileAccess.Write))
                    {
                        byte[] bytes = new byte[source.Length];
                        source.Read(bytes, 0, (int)source.Length);
                        stream.Write(bytes, 0, (int)source.Length);
                    }
                    return true;
                }
                catch (Exception)
                {
                    return false;
                    throw;
                }
            }
        }

        private static void OnUriSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var image = (Image)o;
            var uri = (Uri)e.NewValue;
            if (!IsEnabled || DesignerProperties.IsInDesignTool)
            {
                // Avoid handing off to the worker thread (can cause problems for design tools)
                image.Source = new BitmapImage(uri);
            }
            else
            {
                lock (_syncBlock)
                {
                    // Enqueue the request
                    _pendingRequests.Enqueue(new PendingRequest(image, uri));
                    Monitor.Pulse(_syncBlock);
                }
            }
        }
        private static void HandleGetResponseResult(IAsyncResult result)
        {
            lock (_syncBlock)
            {
                // Enqueue the response
                _pendingResponses.Enqueue(result);
                Monitor.Pulse(_syncBlock);
            }
        }
        private class PendingRequest
        {
            public Image Image { get; private set; }
            public Uri Uri { get; private set; }
            public PendingRequest(Image image, Uri uri)
            {
                Image = image;
                Uri = uri;
            }
        }
        private class ResponseState
        {
            public WebRequest WebRequest { get; private set; }
            public Image Image { get; private set; }
            public Uri Uri { get; private set; }
            public ResponseState(WebRequest webRequest, Image image, Uri uri)
            {
                WebRequest = webRequest;
                Image = image;
                Uri = uri;
            }
        }
        private class PendingCompletion
        {
            public Image Image { get; private set; }
            public Uri Uri { get; private set; }
            public Stream Stream { get; private set; }
            public PendingCompletion(Image image, Uri uri, Stream stream)
            {
                Image = image;
                Uri = uri;
                Stream = stream;
            }
        }
    }
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-66034-1-1.html 上篇帖子: Windows 7英文版设置Python的环境变量 下篇帖子: windows 7下安装oracle 10g client [转]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表