Loading inform pattern
記錄在 Unity 中,實作載入任務的 patterns。在任務開始前開啟工作提示 (like activity inform 或是載入進度條),結束後關閉工作提示 。工作提示可以是開啟顯示進度條,或是其他任何可以提示使用者的顯示物件,在這次範例使用手持平台用的 ActivityIndicator,細節請參考 Unity 文件。
// 手機平台限定 (Android, IOS...),會出現像首圖的動畫,提示目前有工作正在運作
// 開啟
Handheld.StartActivityIndicator();
// 關閉
Handheld.StopActivityIndicator();
因此載入任務範例如下,使用加載網路資源為範例,但可以是其他需等待的工作,例如檔案存取 (File read/ write),關卡載入 (Level Load) 等等:
IEnumerator DoTask() {
Handheld.StartActivityIndicator();
// Do task
var req = UnityWebRequest.Get("http://example.com");
yield return req.Send();
// Do other tasks...
Handheld.StopActivityIndicator();
}
考慮任務失敗的錯誤處理,在處理完錯誤後,關閉工作提示:
IEnumerator DoTask2() {
Handheld.StartActivityIndicator();
// Do task
var req = UnityWebRequest.Get("http://example.com");
yield return req.Send();
if (req.isError) {
// TODO: Handle error
Handheld.StopActivityIndicator();
yield break;
}
// Do other tasks...
Handheld.StopActivityIndicator();
}
但這樣有點不乾淨,多個錯誤處理結束都需要關閉工作提示,這要不就得複製/貼上這麼多段的關閉工作提示的程式碼?或許改用 goto 可以讓程式碼乾淨許多:
IEnumerator DoTask3() {
Handheld.StartActivityIndicator();
// Do task
var req = UnityWebRequest.Get("http://example.com");
yield return req.Send();
if (req.isError) {
// TODO: Handle error
goto END_TASK;
}
// Do other tasks...
END_TASK:
Handheld.StopActivityIndicator();
}
但 goto 不是每個人都可以接受的,因此想到 try/ finally:
IEnumerator DoTask4() {
Handheld.StartActivityIndicator();
try {
// Do task
var req = UnityWebRequest.Get("http://example.com");
yield return req.Send();
if (req.isError) {
// TODO: Handle error
yield break;
}
// Do other tasks...
} finally {
Handheld.StopActivityIndicator();
}
}
但既然使用 try/ finally,就不得不想到 using 以及 IDisposable,因此建立 TaskIndicator 改成以下:
struct TaskIndicator: System.IDisposable {
public static TaskIndicator Create() {
Handheld.StartActivityIndicator();
return new TaskIndicator();
}
public void Dispose() {
Handheld.StopActivityIndicator();
}
}
IEnumerator DoTask5() {
using (TaskIndicator.Create()) {
// Do task
var req = UnityWebRequest.Get("http://example.com");
yield return req.Send();
if (req.isError) {
// TODO: Handle error
yield break;
}
// Do other tasks...
}
}
簡單明瞭,用了 using 來處理關閉工作提示,在離開 using block 會呼叫 TaskIndicator.Dispose。未來也容易擴充,例如加入設定 Progress 的功能:
partial struct TaskIndicator: System.IDisposable {
float progress;
public float Progress {
get {
return this.progress;
}
set {
this.progress = value;
// TODO: Display progress on UI system
}
}
}
IEnumerator DoTask6() {
using (var indicator = TaskIndicator.Create()) {
...
indicator.Progress = 0.5f;
...
}
}
或者採用 Controller & View 分離,採用更簡單的方式,多一層 Coroutine 處理:
IEnumerator DoTaskAndIndicator(IEnumerator task) {
Handheld.StartActivityIndicator();
yield return this.StartCoroutine(task);
Handheld.StopActivityIndicator();
}
沒有留言: