之前也加过延迟处理, 也是有概率出问题, 现在在写的是在异步前就进行控制, 异步中继续控制, 异步结束持续控制.
下面的代码是之前出问题的代码
/**
* 设置远程图片 (监听 sprite 自动回收)
* that.cacheLoad 在执行的时候行为很乱
* @param sprite
* @param type
* @param bundle
* @param info
* @param loadTime 操作的时间, 用于判断是否是异步
* @returns
*/
public setSprite(sprite: Sprite | null | undefined, type: GAssetLoadType, bundle: string, info: string): Promise<Sprite | null> {
return new Promise(async (resolve) => {
if (sprite) {
const doKey2 = `${$g.now} ${Math.random()}`
let doKey = this._handleKey(sprite)
const tempURL = type === GAssetLoadType.Remote ? this.asset.killCache(info) : info
if (sprite.spriteFrame) {
// 检查图片是否没有变化
// texture.nativeUrl 用于本机资产的可序列化URL。供内部使用
const texture = sprite.spriteFrame.packable ? sprite.spriteFrame.original?._texture : sprite.spriteFrame.texture
if (texture instanceof Texture2D && texture._mipmaps && texture.image?.nativeUrl === tempURL) {
return resolve(sprite)
}
// 清理老的贴图
this.clear(sprite)
doKey = this._handleKey(sprite)
}
//下载新资源
if (info) {
// const assetPath = that.asset.getAssetPath(type, bundle, info)
// let cache: { time: number; assetPath: string; } | null = null
// if (that.cacheLoad.has(sprite.uuid)) {
// cache = that.cacheLoad.get(sprite.uuid)!
// cache.time = $g.now
// cache.assetPath = assetPath
// } else {
// cache = { time: $g.now, assetPath: assetPath }
// that.cacheLoad.set(sprite.uuid, cache)
// }
let imageAsset: ImageAsset | null = await this.asset.get(type, bundle, info)
if (imageAsset) {
let log!: GAssetManagerLogAssetType
let logHandle!: GAssetManagerLogAssetHandleType
if ($g.DEBUG) {
log = this.asset.assetLogURLAsset(imageAsset.nativeUrl, imageAsset.uuid)
log.type = type
log.bundle = bundle
log.info = info
log.refCount = imageAsset.refCount
logHandle = {
component: sprite.name,
path: $c.getNodePath(sprite.node),
uuid: `${sprite.uuid} ${isValid(sprite, true)} node:${sprite.node?.uuid ?? ''} url:${imageAsset.nativeUrl}`,
refCount: imageAsset.refCount,
type: 0,
time: $g.now,
stack: new Error().stack ?? '',
key: sprite[this.HandleKey],
keySprite: sprite[this.HandleKey],
}
logHandle.stack = doKey2
log.handle.push(logHandle)
}
// cache = null
// if (that.cacheLoad.has(sprite.uuid)) cache = that.cacheLoad.get(sprite.uuid)!
// && imageAsset.width > 0 && imageAsset.height > 0 过度释放会造成
// 异步后图片可能已经被设置了对的图集
let reImageAsset: ImageAsset | null = null
if (isValid(sprite, true) && sprite[this.HandleKey] === doKey) {
// 如果未对本图进行异步操作, 并且突然有图了
if (sprite.spriteFrame) {
const texture = sprite.spriteFrame.packable ? sprite.spriteFrame.original?._texture : sprite.spriteFrame.texture
if (texture instanceof Texture2D && texture._mipmaps && texture.image?.nativeUrl === tempURL) {
reImageAsset = texture.image
}
// 清理老的贴图
if (!reImageAsset) {
this.clear(sprite)
doKey = this._handleKey(sprite)
if ($g.DEBUG) {
logHandle.key = doKey
logHandle.keySprite = sprite[this.HandleKey]
}
}
}
if (!reImageAsset) {
// if (cache && cache.assetPath === assetPath && isValid(sprite, true)) {
// that.cacheLoad.delete(sprite.uuid)
const texture = new Texture2D()
texture.image = imageAsset
const spriteFrame: SpriteFrame = new SpriteFrame()
spriteFrame.texture = texture
sprite.spriteFrame = spriteFrame
imageAsset.addRef()
texture.addRef()
spriteFrame.addRef()
if ($g.DEBUG) {
log.refCount = imageAsset.refCount
logHandle.refCount = imageAsset.refCount
logHandle.type = 1
// 检查相同 sprite 和 url 下是否有未释放
// let oldRef = 0
// for (let e = 0; e < log.handle.length; e++) {
// const old = log.handle[e]
// if (old.uuid === logHandle.uuid) oldRef += old.type
// }
// if (oldRef > 1) {
// $g.logErr('[GSprite]出现未释放元素')
// }
$g.log(`[GSprite][Ref:${imageAsset.refCount}]`, log)
}
return resolve(sprite)
}
}
// if (cache) that.cacheLoad.delete(sprite.uuid)
// 当A,B 下 url1,A改下url2, 完成url2, 这时A后完成url1(A会释放url1), 然后B完成url2, url2获取内容可能已被A释放
// 这里过度释放
// await $g.timer.baseSleep(10)
if (imageAsset.refCount < 1 && (reImageAsset === null || reImageAsset !== imageAsset)) {
$g.log(assetManager.assets)
// 这里会出现过度释放, 连续的加载, 删除后后面还会有用
switch (type) {
case GAssetLoadType.Remote:
case GAssetLoadType.Base64:
assetManager.releaseAsset(imageAsset)
break;
case GAssetLoadType.Resources:
resources.release(info)
break;
case GAssetLoadType.Bundle:
const b = await this.asset.getBundle(bundle)
if (b) b.release(info)
break;
}
if ($g.DEBUG) {
log.isDestroy = true
logHandle.type = -1
}
imageAsset.destroy()
}
if ($g.DEBUG) $g.log(`[GSprite][丢弃][Ref:${log.refCount}]key:${doKey} sKey:${sprite[this.HandleKey]}`, log)
return resolve(null)
}
}
}
resolve(null)
})
}