unity 轻型UnityWebRequest 加载

项目内需要从web服加载texture,整理了一版简单的纹理管理,包含加载,卸载,控制同时加载数量
1、封装一个LoadingTexture,包含开始下载,中断,callback,释放,是否正在下载,是否开始下载(如果不需要控制下载数量,此属性可不要)

    class LoadingTexture
    {
    
    
        private UnityWebRequest www;
        private string mUrl;
        private List<Action<string, Texture>> mCallback = new List<Action<string, Texture>>();
        bool mIsStarted = false;
        public LoadingTexture(string url, Action<string, Texture> callback)
        {
    
    
            mUrl = url;           
            mCallback.Add(callback);
        }

        public bool IsStarted()
        {
    
    
            return mIsStarted;
        }

        public void StartLoad()
        {
    
    
            mIsStarted = true;

            System.Uri uri = new System.Uri(mUrl);
            //如果不需要读写,第二个参数改为true,节省内存
			www = UnityWebRequestTexture.GetTexture(uri,true);
			www.SendWebRequest();
		}

        public string GetUrl()
        {
    
    
            return mUrl;
        }

        public void AddCallback(Action<string, Texture> callback)
        {
    
    
            mCallback.Add(callback);
        }

        public void RemoveCallback(Action<string, Texture> callback)
        {
    
    
            mCallback.Remove(callback);
            //如果没人需要了,就中断吧
            if (mCallback.Count == 0)
            {
    
    
                if (www != null)
                {
    
    
                    www.Abort();
                    www.Dispose();
                    www = null;
                }
            }
        }

        public bool IsDone()
        {
    
    
            if (www != null)
            {
    
    
                return www.isDone;
            }

            return true;
        }

        public Texture GetTexture()
        {
    
    
            if (www == null)
            {
    
    
                return null;
            }
            if (!www.isDone)
            {
    
    
                return null;
            }

            if (www.isNetworkError || www.isHttpError)
            {
    
    
                return null;
            }

            if(www.downloadHandler == null)
			{
    
    
                return null;
			}
			//如果调用压缩,该texture需要改为可读写,并不能节省内存
            //Texture2D tex = ((DownloadHandlerTexture)www.downloadHandler).texture;
            //tex.Compress(false);
            //return tex;
            return ((DownloadHandlerTexture)www.downloadHandler).texture;
        }

        public void DoCallback()
        {
    
    
            Texture texture = GetTexture();
            foreach ( var callback in mCallback)
            {
    
    
                callback?.Invoke(mUrl, texture);
            }
        }

        public void Dispose()
        {
    
    
            if (www != null)
            {
    
    
                www.Dispose();
                www = null;
            }
        }       
    }

2、添加管理加载流程的Manager,包含TexturePool,需要下载的LoadTextureList,需要释放的ReleaseList,同时下载的数量MaxLoadingTextureCount

     	int MaxLoadingTextureCount = 3;
        //不能用Dictionary,不能保证执行按照加载顺序
        //private Dictionary<string, LoadingTexture> mDicLoadingTexture = new Dictionary<string, LoadingTexture>();
        List<LoadingTexture> mLisLoadingTexture = new List<LoadingTexture>();
        Dictionary<string, Texture> mTexturePool = new Dictionary<string, Texture>();
        //有可能一个Texture被多个引用,所以当一个Texture不需要时,要遍历是否还有引用
        List<Texture> mTryReleaseTexture = new List<Texture>();
        
        //下载函数
        //被调用时先去池子里找,如果池子里有直接返回
        //再去下载池子里找,如果有把回调加到该loadingtexture里
        //都没有,new 一个 loadingtexture放进下载池子
        public void LoadTexture(string url, Action<string, Texture> callback)
        {
    
    
            //当前容器
            if (mTexturePool .ContainsKey(url))
            {
    
    
                Texture workTexture = mWorkTexture[url];
                callback?.Invoke(url, workTexture);
                return;
            }
            //正在下载,有可能多个地方引用
            LoadingTexture loadingTexture = GetLoadingTexture(url);
            if (loadingTexture != null)
            {
    
    
                if (callback != null)
                {
    
    
                    loadingTexture.AddCallback(callback);
                }
                return;
            }
            //创建www去下载
            mLisLoadingTexture.Add(new LoadingTexture(url, callback));
			
            //如果没有正在下载的,启动当前的下载任务,下载一个一个顺利执行
//             if (mLisLoadingTexture.Count == 1)
//             {
    
    
//                 mLisLoadingTexture[0].StartLoad();
//             }

        }
		//把下载成功的texture放进池子里,每次加载成功后调用
        public void AddTexture(string url, Texture texture)
        {
    
    
            if(!mTexturePool.ContainsKey(url))
			{
    
    
                mTexturePool.Add(url, texture);
            }
        }

        //通过url获取loadtexture
        LoadingTexture GetLoadingTexture(string url)
        {
    
    
            foreach (var loadingTexture in mLisLoadingTexture)
            {
    
    
                if (loadingTexture.GetUrl() == url)
                {
    
    
                    return loadingTexture;
                }
            }
            return null;
        }

        //这种方式不确定能正确的移除
        public void CancelLoadTexture(Action<string, Texture> callback)
        {
    
    
            foreach (var loadingTexture in mLisLoadingTexture)
            {
    
    
                loadingTexture.RemoveCallback(callback);
            }
        }

        //尝试Texture是否被需要
        public void TryReleaseTexture(Texture texture)
        {
    
    
			for (int i = 0; i < mLisLoadingTexture.Count; ++i)
			{
    
    
				if (mLisLoadingTexture[i].GetTexture() == texture)
				{
    
    
					return;
				}
			}
			mTryReleaseTexture.Add(texture);
		}
		//通过URL从池子里取出texture
        public Texture GetTextureByUrl(string url)
        {
    
    
            if (mTexturePool.ContainsKey(url))
            {
    
    
                return mTexturePool[url];
            }
            return null;
        }
		//通过texture取出url
        public string GetUrlByTexture(Texture texture)
        {
    
    
            var eTexture = mTexturePool.GetEnumerator();
            while (eTexture.MoveNext())
            {
    
    
                if (eTexture.Current.Value == texture)
                {
    
    
                    return eTexture.Current.Key;
                }
            }
            return null;
        }

        private float nextTimer = 0;
        private float gap = 0.5f;
        //每帧调用下载,每隔0.5f,调用释放
        void Update()
        {
    
    
            UpdateLoading();
            if(Time.time > nextTimer)
			{
    
    
                UpdateTryReleaseTexture();
                nextTimer = Time.time + gap;
            }
        }
		//下载函数,如果下载列表为空,return
		//遍历下载列表,控制同时load数量为3
		//loadingtexture下载完成后remove该任务
		//将下载成功的对象AddToPool
		//Invoke callback
		//释放www
        void UpdateLoading()
        {
    
    
            if (mLisLoadingTexture.Count == 0)
            {
    
    
                return;
            }
            for( int i = 0; i < MaxLoadingTextureCount && i < mLisLoadingTexture.Count; /*++i*/)
            {
    
    
                var loadingTexture = mLisLoadingTexture[i];
                if (!loadingTexture.IsStarted())
                {
    
    
                    loadingTexture.StartLoad();
                }
                if (!loadingTexture.IsDone())
                {
    
    
                    ++i;
                    continue;
                }
                //下载完删除任务
                mLisLoadingTexture.RemoveAt(i);

                var texture = loadingTexture.GetTexture();
                if (texture != null)
                {
    
    
                    //加载成功先保存Texture,再执行回调
                    mTexturePool.Add(loadingTexture.GetUrl(), texture);
                    loadingTexture.DoCallback();
                }
                else
                {
    
    
                    //失败就不回调了,这里打个log吧
                }
                //释放www资源
                loadingTexture.Dispose();
            }         
        }

        int releaseCount = 0;
        int MAX_RELEASE_COUNT = 8;
        //释放函数
        //本来想实现,判断texture无引用,调用UnloadAsset
        //发现这个函数只能卸载从磁盘下载的texture,不能卸载从web服下载的texture
        //后来改成无引用的texture count > 8,直接调用UnloadUnusedAssets
        //经测试不调用destory 也能被清理掉,考虑版本已验收就不改了
        void UpdateTryReleaseTexture()
        {
    
    
			if (releaseCount > MAX_RELEASE_COUNT)
			{
    
    
				Resources.UnloadUnusedAssets();
				releaseCount = 0;
			}
			if (mTryReleaseTexture.Count == 0)
            {
    
    
                return;
            }
            //获取第一个Texture,每次只处理一个
            var texture = mTryReleaseTexture[0];
            //无论是否成功,都先移除
            mTryReleaseTexture.RemoveAt(0);

            //取出所有的引用
            var workPoints = GetAllTexturePoint();
            foreach (var workPoint in workPoints)
            {
    
    
                if (workPoint != null)
                {
    
    
                    //发现有被引用,直接返回
                    if (workPoint .Texture == texture)
                    {
    
    
                        return;
                    }
                }
            }

            //执行到这说明texture没有被引用了
            //先从TexturePool里移除
            string url = GetUrlByTexture(texture);
            if (url == null)
            {
    
    
                return;
            }
            mTexturePool.Remove(url);
            Destroy(texture);
            releaseCount++;
            //直接卸载
            //Resources.UnloadAsset(texture);
        }

		//清理函数,离开运行环境时调用
		//clear Pool 之后调用UnloadUnusedAssets
		public void Clear()
        {
    
    
            mTryReleaseTexture.Clear();
            foreach (var t in mTexturePool.Values)
            {
    
    
                Destroy(t);
                //Resources.UnloadAsset(t);
            }
            mTexturePool.Clear();
            Resources.UnloadUnusedAssets();      
        }
    }

猜你喜欢

转载自blog.csdn.net/u014481027/article/details/125413289
今日推荐