之前可能也有群友写过一些关于ET框架中TimerComponent的使用教程,我这里写下关于TimerComponent的常规使用跟一些不常规使用的方法以及一些情况下需要使用到的不同的函数。
先来看看TimerComponent中都有哪几个方法,
常规的写法,先来个常规计时器,例子放在登录UI中示例,代码如下,此时能发现运行后,登录按钮开始一秒一秒计时,当我们点击登录按钮,此刻服务端返回消息要切换到大厅界面,登录界面销毁,此刻中的协程仍在TimerComponent中缓存,因为等待时间未到的缘故,于是当在时间到了之后,协程里头的执行的给Text赋值,Text已经不存在,此时会报空引用错误。也就是协程没有绑定UI的生命周期。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 定义 private TimerComponent timer = ETModel.Game.Scene.GetComponent(); // 计时器方法, 本方法放在UILoginComponent中作为示例 private async void Counter() { int count = 0; while (true) { await this.timer.WaitAsync(1000); loginBtn.GetComponentInChildren().text = $"登录{count}s"; count++; } } |
此刻我们该怎么解决协程生命周期绑定UI周期这个东东呢? Unity官方的协程Coroutine是绑定MonoBehavior周期的,ET中不适用Mono的情况下,TimerComponent提供了一个CancellationToken方案,可以用于绑定生命周期。下面依旧是定期器为例子,做些修改,调用的方法由WaitAsync(long time)变成WaitAsync(long time, CancellationToken cancellationToken),调用的时候传入一个取消标志,销毁UI的时候调用Cancel就可以把当前不想处理的UI相关的协程从Task池中移除出来。WaitAsync中有个CancellationToken的标志,TimerComponent中注册了Cancel的执行方法,当执行Cancel的时候,TimerComponent中将不会存在关于此CancellationToken的协程
1 2 3 4 5 6 7 8 9 |
public Task WaitAsync(long time, CancellationToken cancellationToken) { TaskCompletionSource tcs = new TaskCompletionSource(); Timer timer = new Timer { Id = IdGenerater.GenerateId(), Time = TimeHelper.Now() + time, tcs = tcs }; this.timers[timer.Id] = timer; this.timeId.Add(timer.Time, timer.Id); cancellationToken.Register(() => { this.Remove(timer.Id); }); return tcs.Task; } |
具体区别的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// define private TimerComponent timer = ETModel.Game.Scene.GetComponent(); CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken cancelLogin; // 初始化 public void Awake() { ReferenceCollector rc = this.GetParent().GameObject.GetComponent(); loginBtn = rc.Get("LoginBtn"); loginBtn.GetComponent().onClick.Add(OnLogin); this.account = rc.Get("Account"); this.cancelLogin = (CancellationToken)this.tokenSource.Token; Counter(); } // 定时器方法调用的区别 private async void Counter() { int count = 0; while (true) { await this.timer.WaitAsync(1000, this.cancelLogin); loginBtn.GetComponentInChildren().text = $"登录{count}s"; count++; } } // 从登陆界面跳转大厅界面 的时候,先执行Cancel的方法,将登陆界面的协程从TimerComponent中移除掉,这样就不会抱空引用错误了 private void OnLogin() { this.tokenSource.Cancel(); Game.Scene.GetComponent().Create(UIType.UILobby); Game.Scene.GetComponent().Remove(UIType.UILogin); } |
本文固定链接: http://www.flamesky.xyz/?p=14
转载请注明: Flamesky 2018年04月22日 于 Flamesky 发表