应通过 UAssetManager::GetStreamableManager() 获取全局唯一的 FStreamableManager 实例,而非自行 new;构造 FSoftObjectPath 须用完整格式如 Texture2D'/Game/Assets/MyTex.MyTex';回调中须用 GetLoadedAsset() 获取资源,不可用 FindObject。

怎么拿到可用的 FStreamableManager 实例
别自己 new 一个 FStreamableManager,它不是普通对象,而是引擎内置的流式资源管理器。UE4.26 起,UAssetManager::GetStreamableManager() 就是标准用法,全局唯一、线程安全、已初始化好。
常见错误是手动在类里声明 FStreamableManager m_Streamable; 然后试图调用 RequestAsyncLoad —— 这会导致崩溃或静默失败,因为没注册到 GC 系统,也不参与引擎生命周期管理。
- 正确做法:统一通过
UAssetManager::GetStreamableManager()获取引用 - 如果项目没启用
AssetManager(比如没在DefaultEngine.ini配置+ActiveGameNameRedirects=(OldGameName="YourGame",NewGameName="YourGame")),需先确保AssetManager已启用,否则该函数返回空指针 - 不需要头文件额外 include,
UAssetManager.h在Engine/Source/Runtime/Engine/Public/AssetManager/AssetManager.h,但通常UObject/UnrealType.h或GameFramework/GameModeBase.h已间接包含
怎么构造合法的 FSoftObjectPath 数组
FStreamableManager::RequestAsyncLoad 只认 FSoftObjectPath,不是字符串路径,也不是硬指针。传错类型会编译失败或加载静默跳过。
常见错误是直接拼接 FString 后强转,或误用 FindObject 返回的硬指针地址当作路径。
- 正确写法:
FSoftObjectPath(FString(TEXT("Texture2D'/Game/Assets/MyTex.MyTex'"))) - 路径格式必须完整:资产类型 + 引号包裹的包内路径 + 点号 + 资产名(与资产文件名一致)
- 批量构建时建议用
TArray<fsoftobjectpath></fsoftobjectpath>,避免反复构造临时对象;不要用FStringAssetReference(已废弃,仅兼容旧代码) - 路径中不能含变量插值错误,例如
TEXT("%%s%%s")漏掉一个%会导致FSoftObjectPath构造为空,后续加载无反应
RequestAsyncLoad 回调时机和资源获取方式
回调函数执行时,资源不一定已“可用”——它只表示加载请求已结束(成功/失败/取消),但 UObject 实例可能还在 GC 队列边缘晃荡。
典型现象:回调里用 FindObject 找不到对象,或找到后立刻被 GC 掉,AddToRoot() 没加对地方。
- 必须在回调中用
UAssetManager::GetStreamableManager().GetLoadedAsset()获取资源,而不是FindObject;后者只查当前 UObject 子系统缓存,不保证是本次加载结果 - 若需长期持有,对返回的
UObject*调用AddToRoot();但注意:每个AddToRoot()必须配对RemoveFromRoot(),否则内存泄漏 - 更稳妥的做法是让资源被某个长期存活的 UObject(如
GameInstance或自定义UDataAsset)持有引用,避免裸指针管理 - 回调函数签名必须匹配
FStreamableDelegate,即void()无参形式;用FStreamableDelegate::CreateLambda时注意捕获列表生命周期,别捕获局部变量
异步加载失败怎么定位
加载失败往往不报错,只静默跳过,或者回调执行但资源为空。根本原因通常是路径不存在、包未打包、或资源未包含在目标平台构建中。
别依赖日志里的 “Load X Failed!!!”,那只是你代码写的 log,不是引擎真实错误。
- 开启详细日志:
LogStreaming: Verbose,运行时输入控制台命令log LogStreaming Verbose - 检查
FStreamableHandle返回值:if (!Handle.IsValid())表示请求根本没发出去(参数非法);if (!Handle->HasLoadCompleted())表示还在加载中 - 用
UAssetManager::Get().GetLoadedAsset(YourSoftPath)在回调前后分别查一次,确认是否真没加载,还是只是没及时注册进 UObject 系统 - 打包后路径大小写敏感:开发时 Windows 不敏感,但 Android/iOS 区分大小写,
/Game/Textures/TEX.png和/Game/Textures/tex.png是两个路径
FStreamableManager 的坑不在 API 复杂,而在它和 UObject 生命周期、GC、打包流程深度耦合。最常被忽略的是:**回调函数执行 ≠ 资源已安全挂载到 UObject 系统**,必须用引擎提供的获取接口,而不是自己猜。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











