Beispiel #1
0
    /// <summary>
    /// 强制卸载指定资源(不管AB加载后属于哪一种类型,强制卸载)
    /// </summary>
    /// <param name="abname"></param>
    public void forceUnloadSpecificResource(string abname)
    {
        ResourceLoadType     resourceloadtype = ResourceLoadType.NormalLoad;
        AbstractResourceInfo arinfo           = null;

        foreach (var loadedabinfomap in mAllLoadedResourceInfoMap)
        {
            if (arinfo != null)
            {
                break;
            }

            foreach (var loadedabinfo in loadedabinfomap.Value)
            {
                if (loadedabinfo.Key.Equals(abname))
                {
                    arinfo           = loadedabinfo.Value;
                    resourceloadtype = loadedabinfomap.Key;
                    break;
                }
            }
        }

        if (arinfo != null)
        {
            mAllLoadedResourceInfoMap[resourceloadtype].Remove(arinfo.AssetBundleName);
            arinfo.dispose();
            ResourceLogger.log(string.Format("AB资源 : {0}已强制卸载!", abname));
        }
        else
        {
            ResourceLogger.logErr(string.Format("AB资源 : {0}未被加载,无法强制卸载!", abname));
        }
    }
    /// <summary>
    /// AB加载携程
    /// </summary>
    /// <returns></returns>
    private IEnumerator assetBundleLoadAsync()
    {
        while (true)
        {
            if (ABAsyncQueue.Count > 0)
            {
                CurrentLoadingAssetBundleLoader = ABAsyncQueue.Dequeue();
                //检查是否已经同步加载完成
                //如果异步加载AB时,同步请求来了,打断异步后续逻辑
                //LoadState == ResourceLoadState.None表明同步加载该资源已经完成,无需再异步返回
                if (CurrentLoadingAssetBundleLoader.LoadState == ResourceLoadState.None)
                {
                    //ResourceLogger.logWar("有资源还未开始异步加载就被同步加载打断!");
                }
                else
                {
                    CurrentLoadingAssetBundleLoader.LoadState = ResourceLoadState.Loading;
                    var abname = CurrentLoadingAssetBundleLoader.AssetBundleName;
                    var abpath = AssetBundlePath.GetABLoadFullPath(abname);
                    AssetBundleCreateRequest abrequest = null;
#if UNITY_EDITOR
                    //因为资源不全,很多资源丢失,导致直接报错
                    //这里临时先在Editor模式下判定下文件是否存在,避免AssetBundle.LoadFromFileAsync()直接报错
                    if (System.IO.File.Exists(abpath))
                    {
                        abrequest = AssetBundle.LoadFromFileAsync(abpath);
                    }
                    else
                    {
                        Debug.LogError(string.Format("AB : {0}文件不存在!", CurrentLoadingAssetBundleLoader.AssetBundleName));
                    }
#else
                    abrequest = AssetBundle.LoadFromFileAsync(abpath);
#endif
                    yield return(abrequest);

                    //如果异步加载AB时,同步请求来了,打断异步后续逻辑
                    //LoadState == ResourceLoadState.None表明同步加载该资源已经完成,无需再异步返回
                    if (CurrentLoadingAssetBundleLoader.LoadState == ResourceLoadState.None)
                    {
                        ResourceLogger.log(string.Format("资源 : {0}加载已完成,异步加载被打断!", abname));
                    }
                    else
                    {
                        var assetbundle = abrequest.assetBundle;
                        if (assetbundle == null)
                        {
                            ResourceLogger.logErr(string.Format("Failed to load AssetBundle : {0}!", CurrentLoadingAssetBundleLoader.AssetBundleName));
                        }
                        CurrentLoadingAssetBundleLoader.onSelfABLoadComplete(assetbundle);
                    }
                }
                CurrentLoadingAssetBundleLoader = null;
            }
            else
            {
                yield return(null);
            }
        }
    }
 /// <summary>
 /// 卸载资源(Resources.UnloadAsset遍历卸载)
 /// </summary>
 private void unloadResource()
 {
     ResourceLogger.log(string.Format("卸载资源:{0}", AssetBundleName));
     foreach (var loadedasset in mLoadedAssetMap)
     {
         var asset = loadedasset.Value;
         if (asset is GameObject)
         {
             ResourceLogger.log(string.Format("无法通过Resources.UnloadAsset卸载GameObject : {0}资源,后续会清空后通过Resources.UnloadUnsedAsset卸载!", asset.name));
         }
         else if (asset is Component)
         {
             ResourceLogger.log(string.Format("无法通过Resources.UnloadAsset卸载Component : {0}资源,后续会清空后通过Resources.UnloadUnsedAsset卸载!", asset.name));
         }
         else
         {
             //AssetDatabase模式不支持卸载资源,
             //因为并非真实的模拟AssetBundle资源加载行为,只是单纯的把所需资源自身加载进来
             //Resources.UnloadAsset(loadedasset.Value);
             ResourceLogger.log(string.Format("假卸载资源:{0}的Asset : {1}", AssetBundleName, loadedasset.Value.name));
         }
     }
     mLoadedAssetMap.Clear();
     mIsReady = false;
 }
Beispiel #4
0
    /// <summary>
    /// 获取AB加载全路径(含热更加载逻辑判定)
    /// </summary>
    /// <param name="abname"></param>
    /// <returns></returns>
    public static string GetABLoadFullPath(string abname)
    {
        //TODO:
        //热更逻辑路径判定
        //if(包外有)        // Application.persistentDataPath
        //{
        //    返回包外资源路径
        //}
        //else              // Application.streamingAssetsPath
        //{
        //    返回包内资源路径
        //}
        var outterabfullpath = ABHotUpdatePath + abname;

        if (IsABExitInOutterPath(abname))
        {
            ResourceLogger.log(string.Format("使用包外资源 : {0}", abname));
            return(outterabfullpath);
        }
        else
        {
            ResourceLogger.log(string.Format("使用包内资源 : {0}", abname));
            return(ABBuildinPath + abname);
        }
    }
Beispiel #5
0
 /// <summary>
 /// 真正的请求资源
 /// </summary>
 /// <param name="resname">资源AB名</param>
 /// <param name="completehandler">加载完成上层回调</param>
 /// <param name="loadtype">资源加载类型</param>
 /// <param name="loadmethod">资源加载方式</param>
 protected override void realRequestResource(string resname, LoadResourceCompleteHandler completehandler, ResourceLoadType loadtype = ResourceLoadType.NormalLoad, ResourceLoadMethod loadmethod = ResourceLoadMethod.Sync)
 {
     // 如果资源已经加载完成,直接返回
     if (mAllLoadedResourceInfoMap[ResourceLoadType.NormalLoad].ContainsKey(resname))
     {
         completehandler(mAllLoadedResourceInfoMap[ResourceLoadType.NormalLoad][resname]);
         if (loadtype > ResourceLoadType.NormalLoad)
         {
             updateLoadedResourceInfoLoadType(resname, ResourceLoadType.NormalLoad, loadtype);
         }
     }
     else if (mAllLoadedResourceInfoMap[ResourceLoadType.Preload].ContainsKey(resname))
     {
         completehandler(mAllLoadedResourceInfoMap[ResourceLoadType.Preload][resname]);
         if (loadtype > ResourceLoadType.Preload)
         {
             updateLoadedResourceInfoLoadType(resname, ResourceLoadType.Preload, loadtype);
         }
     }
     else if (mAllLoadedResourceInfoMap[ResourceLoadType.PermanentLoad].ContainsKey(resname))
     {
         completehandler(mAllLoadedResourceInfoMap[ResourceLoadType.PermanentLoad][resname]);
     }
     else
     {
         // 确保同一个资源加载的Loader是同一个
         // 保证同一个资源加载完成时上层所有加载该资源的回调正确
         AssetBundleLoader abloader = null;
         if (mABRequestTaskMap.ContainsKey(resname))
         {
             abloader = mABRequestTaskMap[resname];
             // 之前有请求resname资源,但还未完成
             // 比如先异步请求resname,在异步完成前来了一个同步请求resname
             // 修改加载方式并添加回调,调用同步加载方式,异步加载会在同步加载完成时一起回调
             abloader.LoadMethod                 = loadmethod;
             abloader.LoadType                   = loadtype;
             abloader.LoadABCompleteCallBack    += completehandler;
             abloader.LoadSelfABCompleteNotifier = onABLoadCompleteNotifier;
             if (loadmethod == ResourceLoadMethod.Sync)
             {
                 ResourceLogger.log(string.Format("请求同步加载一个正在异步加载的资源 : {0}", abloader.AssetBundleName));
                 //重置AB加载状态,走同步加载模式
                 abloader.LoadState = ResourceLoadState.None;
                 abloader.startLoad();
             }
         }
         else
         {
             abloader                            = createABLoader(resname);
             abloader.LoadMethod                 = loadmethod;
             abloader.LoadType                   = loadtype;
             abloader.LoadABCompleteCallBack     = completehandler;
             abloader.LoadSelfABCompleteNotifier = onABLoadCompleteNotifier;
             mABRequestTaskMap.Add(resname, abloader);
             abloader.startLoad();
         }
     }
 }
    /*
     * /// <summary>
     * /// 为AB添加指定owner的引用
     * /// 所有owner都销毁则ab引用计数归零可回收
     * /// </summary>
     * /// <param name="owner"></param>
     * private void retainOwner(UnityEngine.Object owner)
     * {
     *  if (owner == null)
     *  {
     *      ResourceLogger.logErr(string.Format("引用对象不能为空!无法为资源:{0}添加引用!", AssetBundleName));
     *      return;
     *  }
     *
     *  foreach (var referenceowner in mReferenceOwnerList)
     *  {
     *      if (owner.Equals(referenceowner))
     *      {
     *          return;
     *      }
     *  }
     *
     *  System.WeakReference wr = new System.WeakReference(owner);
     *  mReferenceOwnerList.Add(wr);
     * }
     *
     * /// <summary>
     * /// 获取AB有效的引用对象计数
     * /// </summary>
     * /// <returns></returns>
     * private int updateOwnerReference()
     * {
     *  for (int i = 0; i < mReferenceOwnerList.Count; i++)
     *  {
     *      UnityEngine.Object o = (UnityEngine.Object)mReferenceOwnerList[i].Target;
     *      if (!o)
     *      {
     *          mReferenceOwnerList.RemoveAt(i);
     *          i--;
     *      }
     *  }
     *  return mReferenceOwnerList.Count;
     * }
     */

    /// <summary>
    /// 卸载AB(AssetBundle.Unload(true)的形式)
    /// </summary>
    private void unloadAssetBundle()
    {
        ResourceLogger.log(string.Format("卸载AB:{0}", AssetBundleName));
        if (Bundle != null)
        {
            // 索引计数为零时调用释放AB和Asset
            Bundle.Unload(true);
        }
        Bundle   = null;
        mIsReady = false;
    }
Beispiel #7
0
 /// <summary>
 /// 打印所有AB依赖信息
 /// </summary>
 public void printAllResourceDpInfo()
 {
     foreach (var abinfo in mAssetBundleDpMap)
     {
         ResourceLogger.log(string.Format("AB Name:{0}", abinfo.Key));
         foreach (var dpfile in abinfo.Value)
         {
             ResourceLogger.log(string.Format("       DP AB Name:{0}", dpfile));
         }
     }
 }
Beispiel #8
0
 /// <summary>
 /// 检查AB包外目录,不存在则创建一个
 /// </summary>
 public static void CheckAndCreateABOutterPathFolder()
 {
     if (Directory.Exists(ABHotUpdatePath))
     {
         ResourceLogger.log(string.Format("AB包外目录:{0}已存在!", ABHotUpdatePath));
     }
     else
     {
         ResourceLogger.log(string.Format("AB包外目录:{0}不存在,新创建一个!", ABHotUpdatePath));
         Directory.CreateDirectory(ABHotUpdatePath);
     }
 }
 /// <summary>
 /// 开始资源加载卸载统计
 /// </summary>
 public void startResourceLoadAnalyse()
 {
     if (ResourceLoadAnalyseSwitch)
     {
         ResourceLoadAnalyseStart = true;
         ResourceLoadAnalyseMap.Clear();
         ResourceLogger.log("开启AB加载统计!");
     }
     else
     {
         ResourceLogger.logErr("请先开启AB资源加载分析开关!");
     }
 }
Beispiel #10
0
 /// <summary>
 /// 更新已加载AB的加载类型
 /// </summary>
 /// <param name="resname">资源名</param>
 /// <param name="oldloadtype">旧的加载类型</param>
 /// <param name="newloadtype">新的家在类型</param>
 protected void updateLoadedResourceInfoLoadType(string resname, ResourceLoadType oldloadtype, ResourceLoadType newloadtype)
 {
     if (mAllLoadedResourceInfoMap[oldloadtype].ContainsKey(resname))
     {
         var abi = mAllLoadedResourceInfoMap[oldloadtype][resname];
         mAllLoadedResourceInfoMap[newloadtype].Add(resname, abi);
         mAllLoadedResourceInfoMap[oldloadtype].Remove(resname);
         ResourceLogger.log(string.Format("已加载的资源 : {0}从资源类型 : {1}更新到资源类型 : {2}!", resname, oldloadtype, newloadtype));
     }
     else
     {
         ResourceLogger.logErr(string.Format("资源类型 : {0}里找不到已加载的资源 : {1},无法更新该资源的加载类型!", oldloadtype, resname));
     }
 }
    /// <summary>
    /// AB资源加载完成
    /// </summary>
    public void onSelfABLoadComplete(AssetBundle ab = null)
    {
        ResourceLogger.log(string.Format("AB:{0}自身加载完成!", AssetBundleName));

        mABInfo = AssetBundleModule.createAssetBundleInfo(AssetBundleName, ab);
        mABInfo.updateLastUsedTime();

        LoadState = ResourceLoadState.SelfComplete;

        // 通知上层自身AB加载完成,移除加载任务
        LoadSelfABCompleteNotifier(this);
        LoadSelfABCompleteNotifier = null;

        loadDepAssetBundle();
    }
 /// <summary>
 /// 加载自身AB
 /// </summary>
 private void loadSelfAssetBundle()
 {
     ResourceLogger.log(string.Format("加载AB:{0}", AssetBundleName));
     if (LoadMethod == ResourceLoadMethod.Sync)
     {
         LoadState = ResourceLoadState.Loading;
         loadAssetBundleSync();
     }
     else
     {
         //异步加载AB修改成限制携程数量,入队列的形式
         //ModuleManager.Singleton.getModule<ResourceModuleManager>().StartCoroutine(loadAssetBundleAsync());
         AssetBundleAsyncQueue.enqueue(this);
     }
 }
Beispiel #13
0
 /// <summary>
 /// 加载资源
 /// </summary>
 private void loadAsset()
 {
     ResourceLogger.log(string.Format("加载资源:{0}", AssetBundleName));
     //暂时默认都当同步处理
     if (LoadMethod == ResourceLoadMethod.Sync)
     {
         LoadState = ResourceLoadState.Loading;
         loadAssetSync();
     }
     else
     {
         LoadState = ResourceLoadState.Loading;
         loadAssetSync();
     }
 }
    /// <summary>
    /// 依赖AB加载完成回调
    /// </summary>
    /// <param name="resinfo">ab加载信息</param>
    private void onDepABLoadComplete(AbstractResourceInfo resinfo)
    {
        var abinfo = resinfo as AssetBundleInfo;

        ResourceLogger.log(string.Format("依赖AB:{0}加载成功!", abinfo.AssetBundleName));
        mDepAssetBundleInfoList.Add(abinfo);
#if UNITY_EDITOR
        //Editor模式下的调试功能
        // 移除已经加载过的,存储来测试查看用
        mUnloadedAssetBundleName.Remove(abinfo.AssetBundleName);
#endif
        mLoadedDepABCount++;
        // 作为依赖AB时并不会触发getAsset || instantiateAsset之类的接口,
        // 依赖于Unity加载依赖AB自动还原的机制,所以这里我们需要手动更新AB资源的最近使用时间
        abinfo.updateLastUsedTime();
        if (mLoadedDepABCount == mDepABCount)
        {
            allABLoadedComplete();
        }
    }
Beispiel #15
0
    /// <summary>
    /// 打印当前资源所有使用者信息以及索引计数(开发用)
    /// </summary>
    public void printAllLoadedResourceOwnersAndRefCount()
    {
        ResourceLogger.log("Normal Loaded AssetDatabase Info:");
        foreach (var adi in mAllLoadedResourceInfoMap[ResourceLoadType.NormalLoad])
        {
            adi.Value.printAllOwnersNameAndRefCount();
        }

        ResourceLogger.log("Preload Loaded AssetDatabase Info:");
        foreach (var adi in mAllLoadedResourceInfoMap[ResourceLoadType.Preload])
        {
            adi.Value.printAllOwnersNameAndRefCount();
        }

        ResourceLogger.log("Permanent Loaded AssetDatabase Info:");
        foreach (var adi in mAllLoadedResourceInfoMap[ResourceLoadType.PermanentLoad])
        {
            adi.Value.printAllOwnersNameAndRefCount();
        }
    }
 /// <summary>
 /// 打印当前AB所有使用者信息以及索引计数(开发用)
 /// </summary>
 public void printAllOwnersNameAndRefCount()
 {
     ResourceLogger.log(string.Format("AB Name: {0}", AssetBundlePath));
     ResourceLogger.log(string.Format("Ref Count: {0}", RefCount));
     if (mReferenceOwnerList.Count == 0)
     {
         ResourceLogger.log("Owners Name : None");
     }
     else
     {
         ResourceLogger.log("Owners Name :");
         for (int i = 0, length = mReferenceOwnerList.Count; i < length; i++)
         {
             if (mReferenceOwnerList[i].Target != null)
             {
                 ResourceLogger.log(string.Format("owner[{0}] : {1}", i, mReferenceOwnerList[i].Target.ToString()));
             }
         }
     }
     ResourceLogger.log(string.Format("Last Used Time: {0}", LastUsedTime));
 }
 /// <summary>
 /// 停止资源加载卸载统计并输出
 /// </summary>
 public void endResourceLoadAnalyse()
 {
     if (ResourceLoadAnalyseSwitch)
     {
         if (ResourceLoadAnalyseStart)
         {
             ResourceLoadAnalyseStart = false;
             outputResourceLoadedInfoDetail();
             ResourceLoadAnalyseMap.Clear();
             ResourceLogger.log("结束资源加载统计!");
         }
         else
         {
             ResourceLogger.logErr("请先启动资源加载统计!");
         }
     }
     else
     {
         ResourceLogger.logErr("请先开启资源资源加载分析开关!");
     }
 }
    /// <summary>
    /// 所有AB加载完成(自身和依赖AB)
    /// </summary>
    private void allABLoadedComplete()
    {
        ResourceLogger.log(string.Format("AB:{0}所有AB加载完成!", AssetBundleName));

        // 所有AB加载完添加依赖AB索引信息并通知上层可以使用了
        foreach (var dploader in mDepAssetBundleInfoList)
        {
            mABInfo.addDependency(dploader);
        }

        LoadState = ResourceLoadState.AllComplete;

        // 所有AB加载完成才算AB Ready可以使用
        mABInfo.mIsReady = true;

        // 通知上层ab加载完成,可以开始加载具体的asset
        LoadABCompleteCallBack(mABInfo);
        LoadABCompleteCallBack = null;

        // 自身AB以及依赖AB加载完成后,AssetBundleLoader的任务就完成了,回收重用
        AssetBundleLoaderFactory.recycle(this);
    }
    /// <summary>
    /// 移除指定拥有者绑定(用于解决上层绑定对象一直存在导致资源无法释放的问题)
    /// </summary>
    /// <param name="owner"></param>
    /// <returns></returns>
    public bool releaseOwner(UnityEngine.Object owner)
    {
        if (owner == null)
        {
            ResourceLogger.logErr(string.Format("引用对象不能为空!无法为资源:{0}解除绑定!", AssetBundlePath));
            return(false);
        }

        var ownerindex = mReferenceOwnerList.FindIndex((ow) => ow.Target.Equals(owner));

        if (ownerindex != -1)
        {
            ResourceLogger.log(string.Format("资源:{0}找到指定绑定对象:{1},解除绑定!", AssetBundlePath, owner));
            mReferenceOwnerList.RemoveAt(ownerindex);
            return(true);
        }
        else
        {
            ResourceLogger.log(string.Format("资源:{0}找不到指定绑定对象:{1},解除绑定失败!", AssetBundlePath, owner));
            return(false);
        }
    }
Beispiel #20
0
    /// <summary>
    /// 资源请求携程
    /// </summary>
    /// <returns></returns>
    private IEnumerator resourcesRequest()
    {
        foreach (var hotupdateres in mTestHotUpdateResourceList)
        {
            var resurl = TestResourceURL + hotupdateres;
            ResourceLogger.log(string.Format("下载资源 : {0}", resurl));
            var webrequest = UnityWebRequest.Get(resurl);
            yield return(webrequest.SendWebRequest());

            if (webrequest.isNetworkError)
            {
                ResourceLogger.logErr(string.Format("{0}资源下载出错!", hotupdateres));
                ResourceLogger.logErr(webrequest.error);
            }
            else
            {
                if (webrequest.isDone)
                {
                    ResourceLogger.log(string.Format("{0}资源下载完成!", hotupdateres));
                    var data = webrequest.downloadHandler.data;
                    //检查包外是否存在同名资源,存在的话需要先删除再存储最新到包外
                    var outterabfullpath = AssetBundlePath.ABHotUpdatePath + hotupdateres;
                    if (AssetBundlePath.IsABExitInOutterPath(hotupdateres))
                    {
                        ResourceLogger.log(string.Format("删除包外资源 : {0}", hotupdateres));
                        File.Delete(outterabfullpath);
                    }
                    using (var fs = File.Create(outterabfullpath))
                    {
                        fs.Write(data, 0, data.Length);
                        fs.Flush();
                        fs.Close();
                        ResourceLogger.log(string.Format("包外资源 : {0}写入完成!", hotupdateres));
                    }
                }
            }
        }
    }
Beispiel #21
0
 /// <summary>
 /// 卸载资源(Resources.UnloadAsset遍历卸载)
 /// </summary>
 private void unloadResource()
 {
     ResourceLogger.log(string.Format("卸载资源:{0}", AssetBundleName));
     foreach (var loadedasset in mLoadedAssetMap)
     {
         var asset = loadedasset.Value;
         if (asset is GameObject)
         {
             ResourceLogger.log(string.Format("无法通过Resources.UnloadAsset卸载GameObject : {0}资源,后续会清空后通过Resources.UnloadUnsedAsset卸载!", asset.name));
         }
         else if (asset is Component)
         {
             ResourceLogger.log(string.Format("无法通过Resources.UnloadAsset卸载Component : {0}资源,后续会清空后通过Resources.UnloadUnsedAsset卸载!", asset.name));
         }
         else
         {
             //AssetDatabase模式下不会真正卸载资源(因为没有真正打AB没有真正的依赖关系,只是假的模拟AB加载)
             //Resources.UnloadAsset(loadedasset.Value);
             ResourceLogger.log(string.Format("卸载资源:{0}的Asset : {1}", AssetBundleName, loadedasset.Value.name));
         }
     }
     mLoadedAssetMap.Clear();
     mIsReady = false;
 }
Beispiel #22
0
    /// <summary>
    /// 真正的请求资源
    /// </summary>
    /// <param name="respath">资源AB路径</param>
    /// <param name="completehandler">加载完成上层回调</param>
    /// <param name="loadtype">资源加载类型</param>
    /// <param name="loadmethod">资源加载方式</param>
    protected override void realRequestResource(string respath, LoadResourceCompleteHandler completehandler, ResourceLoadType loadtype = ResourceLoadType.NormalLoad, ResourceLoadMethod loadmethod = ResourceLoadMethod.Sync)
    {
        // AB运行时统一转成小写,避免和AB打包那方输出的信息不一致
        respath = respath.ToLower();
        var abpath = string.Empty;

        // 因为依赖AB加载也是走统一入口,所以要区分是AB路径还是Asset路径
        if (!mAssetBundleBuildInfo.isABPath(respath))
        {
            // AB依赖信息文件和AB打包
            abpath = getAssetPathAssetBundleName(respath);
        }
        else
        {
            abpath = respath;
        }
        // 如果资源已经加载完成,直接返回
        if (mAllLoadedResourceInfoMap[ResourceLoadType.NormalLoad].ContainsKey(abpath))
        {
            completehandler(mAllLoadedResourceInfoMap[ResourceLoadType.NormalLoad][abpath]);
            if (loadtype > ResourceLoadType.NormalLoad)
            {
                updateLoadedResourceInfoLoadType(abpath, ResourceLoadType.NormalLoad, loadtype);
            }
        }
        else if (mAllLoadedResourceInfoMap[ResourceLoadType.Preload].ContainsKey(abpath))
        {
            completehandler(mAllLoadedResourceInfoMap[ResourceLoadType.Preload][abpath]);
            if (loadtype > ResourceLoadType.Preload)
            {
                updateLoadedResourceInfoLoadType(abpath, ResourceLoadType.Preload, loadtype);
            }
        }
        else if (mAllLoadedResourceInfoMap[ResourceLoadType.PermanentLoad].ContainsKey(abpath))
        {
            completehandler(mAllLoadedResourceInfoMap[ResourceLoadType.PermanentLoad][abpath]);
        }
        else
        {
            // 确保同一个资源加载的Loader是同一个
            // 保证同一个资源加载完成时上层所有加载该资源的回调正确
            AssetBundleLoader abloader = null;
            if (mABRequestTaskMap.ContainsKey(abpath))
            {
                abloader = mABRequestTaskMap[abpath];
                // 之前有请求resname资源,但还未完成
                // 比如先异步请求resname,在异步完成前来了一个同步请求resname
                // 修改加载方式并添加回调,调用同步加载方式,异步加载会在同步加载完成时一起回调
                abloader.LoadMethod                 = loadmethod;
                abloader.LoadType                   = loadtype;
                abloader.LoadABCompleteCallBack    += completehandler;
                abloader.LoadSelfABCompleteNotifier = onABLoadCompleteNotifier;
                if (loadmethod == ResourceLoadMethod.Sync)
                {
                    ResourceLogger.log(string.Format("请求同步加载一个异步加载状态:{0}的资源 : {1}", abloader.LoadState.ToString(), abloader.AssetBundlePath));
                    //重置AB加载状态,走同步加载模式
                    abloader.LoadState = ResourceLoadState.None;
                    abloader.startLoad();
                }
            }
            else
            {
                abloader                            = createABLoader(abpath);
                abloader.LoadMethod                 = loadmethod;
                abloader.LoadType                   = loadtype;
                abloader.LoadABCompleteCallBack     = completehandler;
                abloader.LoadSelfABCompleteNotifier = onABLoadCompleteNotifier;
                mABRequestTaskMap.Add(abpath, abloader);
                abloader.startLoad();
            }
        }
    }