Unity MyFramework 用法说明(十七):使用 WaitingManager 统一等待异步任务与业务条件
上一篇介绍了 AsyncTaskGroup,它适合等待多个异步操作全部完成。
实际业务中,流程开始的条件不一定都是异步任务。例如进入战斗前,除了等待地图加载,还可能需要等待玩家创建完成、服务器场景数据到达。
MyFramework 提供了 WaitingManager,用于把这些等待条件统一封装起来。
项目地址:
https://github.com/ZHOURUIH/MyFramework
一、WaitingManager 解决什么问题
假设进入战斗需要满足三个条件:
地图资源加载完成
玩家角色创建完成
服务器场景数据接收完成
直接写在 update() 中:
public override void update(float elapsedTime)
{
base.update(elapsedTime);
if (!mMapLoaded ||
!mPlayerCreated ||
!mServerDataReady)
{
return;
}
enterBattle();
}
还需要额外保证 enterBattle() 只执行一次,并在流程退出后停止检查。
使用 WaitingManager 后,可以直接描述:
等待什么
↓
全部满足
↓
执行什么
二、等待一个业务条件
最简单的用法是等待一个 BoolFunction 返回 true:
using static FrameBaseHotFix;
protected bool mPlayerCreated;
protected void waitPlayerCreated()
{
mWaitingManager.createWaiting(
() => mPlayerCreated,
onPlayerCreated);
}
protected void onPlayerCreated()
{
log("玩家创建完成");
}
WaitingManager 每帧检查条件。
当条件第一次成立时,会执行完成回调,并自动销毁这个 Waiting。
不需要自己在 update() 中持续判断。
三、同时等待多个条件
通过 createWaiting(Action) 创建一个空的等待对象,再逐项添加条件:
protected bool mPlayerCreated;
protected bool mServerDataReady;
protected bool mSceneInitialized;
protected void waitEnterBattle()
{
Waiting waiting =
mWaitingManager.createWaiting(onEnterBattle);
waiting.addCondition(() => mPlayerCreated);
waiting.addCondition(() => mServerDataReady);
waiting.addCondition(() => mSceneInitialized);
}
protected void onEnterBattle()
{
log("所有条件完成,进入战斗");
}
只有三个条件全部返回 true,才会调用 onEnterBattle()。
完成回调最多执行一次,即使条件之后一直保持为 true,也不会重复触发。
四、同时等待异步操作和业务条件
Waiting 不仅能添加条件,也可以添加 CustomAsyncOperation:
protected bool mPlayerCreated;
protected bool mServerDataReady;
protected void prepareBattle()
{
CustomAsyncOperation mapOperation =
startLoadMap();
Waiting waiting =
mWaitingManager.createWaiting(onPrepareFinished);
waiting.addAsyncOperation(mapOperation);
waiting.addCondition(() => mPlayerCreated);
waiting.addCondition(() => mServerDataReady);
}
protected void onPrepareFinished()
{
log("地图、玩家和服务器数据都已准备完成");
}
protected CustomAsyncOperation startLoadMap()
{
// 启动地图加载并返回对应的异步操作
return null;
}
判断规则是:
所有 CustomAsyncOperation 不再等待
并且
所有 BoolFunction 返回 true
两部分同时满足后,才会执行完成回调。
传入的异步操作和条件不能为 null,否则检查时会出现空引用。
五、快速等待一到三个异步操作
WaitingManager 还提供了常用重载:
mWaitingManager.createWaiting(
operation,
onFinished);
等待两个异步操作:
mWaitingManager.createWaiting(
mapOperation,
playerOperation,
onFinished);
等待三个异步操作:
mWaitingManager.createWaiting(
mapOperation,
playerOperation,
monsterOperation,
onFinished);
如果只有异步操作,不需要额外业务条件,直接使用这些重载更简洁。
任务数量更多,或者还要混合普通条件时,再创建 Waiting 后逐项添加。
六、获取简单进度
Waiting 可以计算当前进度:
float progress = waiting.getProgress();
它会把每一个异步操作和每一个业务条件都视为一项任务。
例如共有四项,其中两项完成:
进度 = 2 / 4 = 0.5
可以用于显示简单的准备进度:
protected Waiting mWaiting;
public float getPrepareProgress()
{
return mWaiting?.getProgress() ?? 1.0f;
}
需要注意,它只是按照完成数量计算,不会读取单个资源加载任务内部的真实百分比。
未完成 计为 0
已完成 计为 1
因此它适合显示整体步骤进度,不适合代替精确的下载进度。
七、等待过程中的取消条件
当所属流程已经退出时,原来的等待回调不应该继续执行。
可以设置取消条件:
protected bool mCanceled;
protected void beginWaiting()
{
mCanceled = false;
Waiting waiting =
mWaitingManager.createWaiting(onFinished);
waiting.addCondition(() => mPlayerCreated);
waiting.addCondition(() => mServerDataReady);
waiting.setCancelCondition(() => mCanceled);
}
protected void leaveCurrentFlow()
{
mCanceled = true;
}
当取消条件返回 true 时:
不执行完成回调
自动销毁 Waiting
默认创建的 Waiting 会自动销毁,所以这里只需要修改取消条件。
取消条件适合处理:
界面已经关闭
SceneProcedure 已经退出
玩家主动取消匹配
当前请求已经被新请求替代
对象准备销毁
八、手动管理 Waiting 生命周期
默认情况下,等待完成或取消后会自动销毁:
Waiting waiting =
mWaitingManager.createWaiting(onFinished);
等价于:
Waiting waiting =
mWaitingManager.createWaiting(onFinished, true);
如果需要保存引用并由业务手动管理,可以关闭自动销毁:
protected Waiting mWaiting;
protected void beginWaiting()
{
mWaiting =
mWaitingManager.createWaiting(
onFinished,
false);
mWaiting.addCondition(() => mPlayerCreated);
mWaiting.addCondition(() => mServerDataReady);
}
完成后手动销毁:
protected void onFinished()
{
mWaitingManager.destroyWaiting(ref mWaiting);
enterBattle();
}
流程提前退出时取消:
protected void cancelWaiting()
{
mWaitingManager?.cancel(ref mWaiting);
}
cancel() 会立即移除并回收等待对象,同时将引用设置为 null,不会调用完成回调。
关闭自动销毁后,必须主动调用:
destroyWaiting(ref waiting);
或者:
cancel(ref waiting);
否则等待对象会一直保留在 WaitingManager 中。
九、空 Waiting 的行为
下面创建了一个没有任何条件的等待对象:
mWaitingManager.createWaiting(onFinished);
没有条件时,Waiting.isDone() 会直接返回 true。
因此它会在 WaitingManager 下一次更新时执行回调,而不是在 createWaiting() 中立即调用。
这可以用来把一段逻辑延迟到下一次框架更新,但最好只在确实需要这种行为时使用。
十、和 AsyncTaskGroup 的区别
两者都能等待多个任务,但侧重点不同。
AsyncTaskGroup
主要等待多个异步操作:
资源A加载
资源B加载
资源C加载
↓
全部完成后回调
适合资源预加载和批量异步初始化。
WaitingManager
可以混合等待:
异步操作
业务布尔条件
服务器数据状态
对象创建状态
↓
全部满足后回调
选择方式可以概括为:
只组合多个异步任务
使用 AsyncTaskGroup
需要同时等待异步任务和业务状态
使用 WaitingManager
十一、总结
WaitingManager 的基本用法是:
Waiting waiting =
mWaitingManager.createWaiting(onFinished);
waiting.addAsyncOperation(operation);
waiting.addCondition(() => conditionA);
waiting.addCondition(() => conditionB);
需要取消时:
waiting.setCancelCondition(() => canceled);
需要手动管理生命周期时:
mWaitingManager.cancel(ref waiting);
它把原本散落在 update()、异步回调和多个布尔字段中的判断,集中成一个明确的等待对象:
添加异步操作
添加业务条件
设置取消条件
全部满足后统一回调
这样进入场景、开始战斗、匹配完成和批量初始化等流程,可以直接表达“需要等待什么”,而不需要在各处重复维护完成判断。
更多推荐


所有评论(0)