之前可能也有羣友寫過一些關於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 發表