Unity图片加载器

来源:互联网 发布:计算机三级数据库 编辑:程序博客网 时间:2024/06/10 04:33

在http://www.tuicool.com/articles/ZFrMZnM的基础上对AsyncImageDownload进行了完善,完整代码如下:


using UnityEngine;
using System.Collections;using System.IO;using System.Collections.Generic;using System;/// <summary>/// 图片(Texture)加载类/// 三级缓存:1、如果在内存中,则先从内存获取;2、没有则查看本地是否存在,存在则从本地获取;3、没有则再从网络进行获取并保存到本地。/// </summary>public class AsyncImageDownload : MonoBehaviour{    /// <summary>    ///  默认图片    /// </summary>    public Texture placeholder;    /// <summary>    /// 单例    /// </summary>    public static AsyncImageDownload Instance = null;    /// <summary>    /// 本地图片保存路径。如果是android环境,Application.persistentDataPath值为/storage/emulated/legacy/Android/data/com.xxx.xxx/files/    /// </summary>    private string imageCacheRootPath = Application.persistentDataPath + "/ImageCache/";    /// <summary>    /// 缓存在内存里的texture,重复利用。key是url对应图片保存成本地文件的绝对路径。    /// texture采用弱引用方式,当系统需要回收时这里不会因为强引用阻止回收。    /// </summary>    private Dictionary<string, WeakReference> textureCache = new Dictionary<string,WeakReference>();    /// <summary>    /// 应用开始运行时,可以调用此方法进行初始化    /// </summary>    /// <returns>AsyncImageDownload单例对象</returns>    public static AsyncImageDownload CreateSingleton()    {        if (!Directory.Exists(Application.persistentDataPath + "/ImageCache/"))        {            Directory.CreateDirectory(Application.persistentDataPath + "/ImageCache/");        }        GameObject obj = new GameObject();        obj.AddComponent<AsyncImageDownload>();        AsyncImageDownload loader = obj.GetComponent<AsyncImageDownload>();        Instance = loader;        loader.placeholder = Resources.Load("default_cover") as Texture;// 默认图片        Debug.Log("image save path : " + Instance.imageCacheRootPath);        return loader;    }    /// <summary>    /// 根据url加载对应图片。    /// </summary>    /// <param name="url">图片url</param>    /// <param name="texture">UITexture</param>    /// <param name="action">加载完成时的回调</param>    /// <param name="needCache">是否需要缓存到内存中(如果非长时间显示在页面,不建议缓存)</param>    public void SetAsyncImage(string url, UITexture texture, Action action = null, bool needCache = true)    {        if (string.IsNullOrEmpty(url))        {            Debug.LogWarning("[SetAsyncImage] url is null.");            return;        }        // 只有需要缓存时才从内存中查找        if (needCache)        {            // 从内存获取            if (getFromCache(imageCacheRootPath + url.GetHashCode(), texture))            {                if (action != null)                {                    action();                }                return;            }        }        //判断是否是第一次加载这张图片(以url的hashcode作为文件名)        if (!File.Exists(imageCacheRootPath + url.GetHashCode()))        {            //如果之前不存在缓存文件            texture.StopCoroutine("DownloadImage");//UITexture.StopCoroutine可以停止之前的已经无用的协程            texture.StartCoroutine(DownloadImage(url, texture, action, needCache));        }        // 从本地加载        else        {            texture.StopCoroutine("LoadLocalImage");            texture.StartCoroutine(LoadLocalImage(imageCacheRootPath + url.GetHashCode(), texture, action, needCache));        }    }    /// <summary>    /// 加载本地图片。缓存到内存里。    /// </summary>    /// <param name="path">本地文件绝对路径</param>    /// <param name="texture">UITexture</param>    /// <param name="action">加载完成时的回调</param>    public void SetLocalImage(string path, UITexture texture, Action action = null)    {        if (string.IsNullOrEmpty(path))        {            Debug.LogWarning("[SetLocalImage] path is null.");            return;        }        // 从内存获取        if (getFromCache(path, texture))        {            if (action != null)            {                action();            }            return;        }        // 先判断该文件是否存在,不存在直接返回(这样会显示默认图片);如果不做这个判断进入LoadLocalImage,界面上会显示成红色问号。        FileInfo fi = new FileInfo(path);        if (!fi.Exists)        {            Debug.LogError("Path is Not Exists! " + path);            return;        }        texture.StopCoroutine("LoadLocalImage");        texture.StartCoroutine(LoadLocalImage(path, texture, action));    }    /// <summary>    /// 清空指定key的缓存    /// </summary>    /// <param name="filePath"></param>    public void clearCache(string filePath)    {        if (textureCache.ContainsKey(filePath))        {            textureCache.Remove(filePath);        }    }    /// <summary>    ///     /// </summary>    /// <param name="url">图片url</param>    /// <param name="texture">UITexture</param>    /// <param name="action">加载完成时的回调</param>    /// <param name="needCache">是否需要缓存到内存中</param>    /// <returns></returns>    IEnumerator DownloadImage(string url, UITexture texture, Action action = null, bool needCache = true)    {                int filename = url.GetHashCode();        Debug.Log("[DownloadImage]downloading new image : " + filename);        yield return new WaitForSeconds(0.008f);//如果界面频繁快速切换,之前的图片根本不需要加载,所以这里稍微延迟一会儿再请求网络。        WWW www = new WWW(url);        yield return www;        if (www.error != null)        {            Debug.LogWarning("[DownloadImage] www.error : " + www.error);            if (action != null)            {                action();            }        }        else        {            Debug.Log("[DownloadImage]download ok : " + filename);            Texture2D image = www.texture;            // The data must be an image in JPG or PNG format. If the data is not a valid image, the generated texture will be a small image of a question mark.(红色问号,大小为8*8)            if (image == null || (image.width == 8 && image.height == 8))//如果image为空,或者为红色问号(无效图片)。            {                Debug.LogError("[DownloadImage]www.texture is null or a question mark, return.");            if (action != null)            {                action();            }            }            else            {                image.wrapMode = TextureWrapMode.Clamp;//将Texture的循环模式设为拉伸,Texture边界设为拉伸就不会出现白线。默认是平铺,如果是平铺的话,可能会出现两张图片交界处显示白线的问题。                texture.mainTexture = image;                if (needCache)                {                    textureCache[imageCacheRootPath + url.GetHashCode()] = new WeakReference(image);                }                if (action != null)                {                    action();                }                //将图片保存至缓存路径                byte[] pngData = www.bytes;                Debug.Log("[DownloadImage] " + filename + " , size : " + (pngData.Length / 1024) + "KB");                File.WriteAllBytes(imageCacheRootPath + filename, pngData);            }        }    }    IEnumerator LoadLocalImage(string filePath, UITexture texture, Action action = null, bool needCache = true)    {        Debug.Log("getting local image :" + filePath);                yield return new WaitForSeconds(0.008f);        WWW www = new WWW("file:///" + filePath);        yield return www;        if (www.error != null)        {            Debug.LogWarning("[LoadLocalImage] www.error : " + www.error);            DeleteFile(filePath);        }        else        {            Texture2D image = www.texture;            //The data must be an image in JPG or PNG format. If the data is not a valid image, the generated texture will be a small image of a question mark.(红色问号,大小为8*8)            if (image == null || (image.width == 8 && image.height == 8))//如果image为空,或者为红色问号(无效图片)。            {                Debug.LogError("www.texture is null or a question mark, delete it.");                DeleteFile(filePath);            }            else            {                image.wrapMode = TextureWrapMode.Clamp;//将Texture的循环模式设为拉伸,Texture边界设为拉伸就不会出现白线。默认是平铺,如果是平铺的话,可能会出现两张图片交界处显示白线的问题。                //直接贴图                texture.mainTexture = image;                if (needCache)                {                    textureCache[filePath] = new WeakReference(image);                }            }        }        if (action != null)        {            action();        }    }    /// <summary>    /// 从textureCache读取    /// </summary>    /// <param name="localPath"></param>    /// <param name="texture"></param>    /// <returns></returns>    private bool getFromCache(string localPath, UITexture texture)    {        if (textureCache.ContainsKey(localPath))        {            WeakReference wr = textureCache[localPath];            if (wr != null && wr.IsAlive)            {                texture.mainTexture = (Texture2D)wr.Target;                if (texture.mainTexture == null)// 有可能在获取到的瞬间被回收了                {                    return false;                }                return true;            }        }        return false;    }    private void DeleteFile(string filePath)    {        FileInfo fi = new FileInfo(filePath);        if (fi.Exists)        {            Debug.LogWarning("[DeleteFile] delete this file : " + filePath);            fi.Delete();        }    }   }




0 0