Praneat Blog

Wongsathorn Phaisarnrungpana
Game Developer
20 Apr 2020

มาใช้ Reactive Extensions for Unity (UniRx) กันเถอะ !!! Part2


สำหรับคนที่อ่าน Part แรกแล้วสงสัยว่า Observable คืออะไร ทำไมต้อง Subscribe , หลัง Subscribe แล้วต้องทำอะไรอีกมั้ย CatchIgnore คืออะไร ใน Part ที่ 2 นี้เราจะมาลงลึกถึงรายละเอียดต่างๆที่อยู่ใน Code ตัวอย่างของ Part แรกกัน.

Observable คืออะไร ?


ใน Part แรกเราจะได้เห็นคำว่า Observable ในตัวอย่าง Code บ่อยมาก (แทบจะทุกตัวอย่าง Code เลยก็ว่าได้) ซึ่งใน Class ของเจ้า Observable นี้จะประกอบไปด้วย Static Method ต่างๆมากมาย โดยในที่นี้เราจะเรียกมันว่า Operator โดยทุกๆ Operator จะ Return เจ้าสิ่งที่เรียกว่า IObservable ออกมาก เพื่อให้เราสามารถ Subscribe มันเพื่อทำอะไรสักอย่างหลังจากที่มันทำงานเสร็จได้ .
ใน UniRx จะมี Class Observable อยู่ 2 Class (แต่หลายๆ Partial Class) คือ Observable กับ ObservableWWW โดยเจ้า Observable จะมี Operator ทั่วไปที่ใช้งานกัน ส่วนเจ้า ObservableWWW จะมี Operator เกี่ยวกับการยิง Request และ Handler Error ต่างๆของการยิง Request.

Operator คืออะไร ?


Operator คือ Static Method ต่างๆที่อยู่ภายใน Class ObservableWWW โดยตัวอย่าง Operator ที่เห็นได้จากตัวอย่างใน Part แรกคือ Get , WhenAll และ CatchIgnore

Get


Get() เป็น Operator ที่ใช้ในการยิง Request ต่างๆ โดยเทียบได้กับการใช้ Coroutine คู่กับ Class WWW ของ Unity ซึ่งเจ้า Operator Get() นั้นมี Parameter ต่างๆดังนี้

string url : เอาไว้ส่ง url ที่เราจะยิง Request

Dictionary<string , string> header : ส่ง header

IProgress progress : parameter นี้เราสามารถนำเอาค่า float (normalize) ที่คืนมา มาทำเป็น Progressbar หรือตัว view ที่บอกกับ user ว่า เจ้าสิ่งที่กำลัง Download อยู่หรือยิง request สำเร็จไปกี่เปอรเซ็นแล้วนะได้

WhenAll

var parallel = Observable.WhenAll(
                    ObservableWWW.Get("http://google.com/"),
                    ObservableWWW.Get("http://bing.com/"),
                    ObservableWWW.Get("http://unity3d.com/"));
parallel.Subscribe(xs =>
{
    Debug.Log(xs[0].Substring(0, 100)); // google
    Debug.Log(xs[1].Substring(0, 100)); // bing
    Debug.Log(xs[2].Substring(0, 100)); // unity
});


WhenAll() เป็น Operator ที่ใช้ในการรอให้ Operator อื่นๆหลายๆตัวทำงานเสร็จทั้งหมดก่อน โดยสิ่งที่จะเกิดขึ้นจากตัวอย่างใน Part แรกคือ ตัว Operator WhenAll() จะรอให้ Operator Get() ทั้ง 3 ตัว (ทำงานพร้อมกันทั้ง 3 ตัว แบบ Pararell) ทำงานเสร็จก่อนทั้ง 3 ตัวแล้วจึงจะทำสิ่งที่ถูกเขียนอยู่ใน Subscribe

CatchIgnore


CatchIgnore เป็น Operator ที่ใช้ในการ Handler Exception ต่างๆ ที่เกิดจากข้อผิดพลาดกจากการยิง Request โดยเราสามารถ Handler Exception ต่างๆที่จะเกืดขึ้นได้ดังนี้

“WWWErrorException”

ObservableWWW.Get("http://www.google.com/404")
                    .CatchIgnore((WWWErrorException ex) =>
                    {
                        Debug.Log(ex.RawErrorMessage);

                        if (ex.HasResponse)
                            Debug.Log(ex.StatusCode);
                        foreach (var item in ex.ResponseHeaders)
                        {
                            Debug.Log(item.Key + ":" + item.Value);
                        }
                    }).Subscribe();



“TimeoutException”

ObservableWWW.Get(“http://www.google.com/”)
                     .Timeout(TimeSpan.FromSeconds(timeout))
                     .CatchIgnore((TimeoutException ex) =>
                     {
                         Debug.Log("DoSomething When Timeout");
                     }).Subscribe();



นอกจาก Default Exception ต่างๆที่ทางUniRx มีให้เราใช้ เรายังสามารถทำ Exception ต่างๆของเราเองแล้วส่งเข้าไปผ่าน Operator ที่ชื่อว่า DoOnError เพื่อให้เจ้า Operator CatchIgnore นั้น Handler Exception เหล่านั้นให้เราด้วยได้ เช่น

ObservableWWW.Get("http://www.google.com/")
                     .DoOnError((ex) =>
                     {
                         bool isNoNetworkConnection = Application.internetReachability == NetworkReachability.NotReachable;

                         if (isNoNetworkConnection)
                             throw new NoInternetConnectionException();

                     }).CatchIgnore((NoInternetConnectionException ex) =>
                     {
                         Debug.Log("Dosomething When NoInternetConnectionException");
                     }).Subscribe();