การพัฒนา Mobile app ทั้ง Android และ iOS นั้น
คงไม่มี developer คนไหนไม่รู้จัก Reactive หรือ Rx
แต่กลับพบว่าหลาย ๆ คนยังไม่เข้าใจที่มาที่ไปว่า
Rx มันเข้ามาช่วยอะไร ?
ก่อนจะมี Rx มีอะไรให้ใช้บ้าง ?
ปัญหาคืออะไร ?
ดังนั้นก่อนที่จะเริ่มนำ Rx มาใช้งาน
กลับมาสู่ความรู้พื้นฐานก่อนดีไหม
ในบทความนี้เน้นไปที่ Android ก่อน
พื้นฐานของ Android app
จะทำงานอยู่บน Thread เดียวเท่านั้น หรือเราเรียกว่า UI Thread หรือ Main Thread ใช้สำหรับการ update หน้า View นั่นเอง ทุกอย่างมันดูดีมาก ๆ แต่ในงานจริง ๆ จะพบว่า เมื่อต้องดึงข้อมูลจากส่วนการทำงานอื่น ๆ เช่น Database, API อาจจะใช้เวลาทำงานนาน ๆ ทำให้ผู้ใช้ต้องรอ รอ รอ แล้วก็รอ !!! เนื่องจากมีเพียง Main Thread เดียวเท่านั้น หรือซ้ำร้ายไปกว่านั้น ระบบอาจจะแสดง dialog แสดง ANR (Application Not Response) ออกมา และบอกให้ผู้ใช้งานปิด app ไปซะ แน่นอนทำให้ app มี responsive ที่แย่มาก ๆ บางครั้งอาจจะแก้ไขปัญหาแบบแก้ผ้าเอาหน้ารอดไปก่อนเช่น แสดง progress bar เพื่อบอก progress การทำงาน (หมุน ๆ ๆ ๆ) เพื่อแสดงให้ผู้ใช้งานเห็นว่า ระบบยังทำงานอยู่นะ ไม่ได้ตาย หรือทำหน้า splash ขึ้นมาเพื่อซ่อนการทำงานแต่สิ่งที่ควรทำคือ แยก process ต่าง ๆ ออกไปทำงานใน Background Thread สิ !!
แน่นอนว่า Android ก็เตรียมไว้ให้เสร็จสรรพแล้ว เช่น- Thread
- IntentService
- AsyncTask
- Loader
- จัดการ callback ใน Main Thread
- จัดการ Error ต่าง ๆ
- แก้ไขปัญหา Callback hell
- จัดการการทำงานใน background process ให้ง่าย ๆ
โดยรวม ๆ แล้วยากใช้ได้เลยนะ !!
จากปัญหาต่าง ๆ เหล่านี้นี่เอง
จึงมีคนพยายามสร้าง library มาช่วย ซึ่งหนึ่งในนั้นก็คื Rx นั่นเอง ในภาษา Java ก็มี RxJava ให้ใช้งาน ส่วนใน Android ก็คือ RxAndroid เรื่อง Rx นั้นสามารถดูเพิ่มเติมได้จาก Marble digagram ทำการอธิบายด้วยรูปภาพ ซึ่งเข้าใจได้ง่ายมาก ๆการทำงานของ Rx ประกอบไปด้วยส่วนหลัก ๆ ดังนี้
- Observable
- Observer
- Operator (มีเยอะมาก ๆ)
- Subscriber
- Scheduler
- Compose Stream
มาลองใช้งานแบบง่าย ๆ กันหน่อย ด้วย Hello World
เพื่อทำความเข้าใจเกี่ยวกับ RxAndroid กัน มีขั้นตอนดังนี้ ขั้นตอนที่ 1 เริ่มต้นด้วยการสร้าง Observable ขึ้นมาก่อน ซึ่งจะส่งข้อมูลออกมาตัวเดียว คือ List ของเพื่อน(String) [gist id="f00f63170493ef4fcd52512f8ba60e0b" file="1.java"] ปล. การทำงานจะไม่รอจนการ method getFriendList() จะทำงานเสร็จนะ หรือทำงานแบบ Non-Blocking ซึ่งแตกต่างจากรูปแบบการเขียนแบบเดิมนะครับ ที่เป็นแบบ Blocking หรือต้องรอนั่นเอง ขั้นตอนที่ 2 ทำการ subscribe ไปที่ Observable คำถามที่น่าสนใจคือ แล้วเราจะรู้ได้อย่างไร ว่า method getFriendList() ทำงานเสร็จ ดังนั้นสิ่งที่ต้องทำคือ การ subscribe นั่นเอง โดยมี life cycle ดังนี้- onCompleted() ถูกเรียกเมื่อการทำงานใน method getFriendList() ทำงานเสร็จสิ้น
- onError() ถูกเรียกเมื่อเกิด error ขึ้นมา
- onNext() ถูกเรียกเมื่อ method getFriendList() ทำงานสำเร็จและนำผลการทำงานมาใช้งาน จากตัวอย่างคือรายชื่อของเพื่อนนั่นเอง
ปล. Observable มันสำคัญมาก ๆ นะ เนื่องจากใช้กำหนดพฤติกรรมการทำงานต่าง ๆ ไว้เลย
ลองมาดูอีกสักตัวอย่าง เป็นการดึงข้อมูลจาก REST API ทำการแบบ Asynchronous
เริ่มต้นด้วยการสร้าง Observable ขึ้นมาเช่นเดิม แต่สิ่งที่แตกต่างจากตัวอย่างแรกคือ ไม่สามารถเรียกใช้ Observable.just() ได้ เนื่องจาก REST API มันจะ block การทำงานของ Main Thread ไว้ ดังนั้นเราต้องให้การเรียก REST API ไปทำงานอีก Thread ดังนี้ [gist id="f00f63170493ef4fcd52512f8ba60e0b" file="2.java"] จากนั้นทำการ subscribe ซะ และต้องกำหนด property ในการเรียกใช้เพิ่มนิดหน่อยดังนี้- subscribeOn() จากตัวอย่างเป็นการ subscribe บน I/O Thread
- observerOn() จากตัวอย่างเป็นการ observer บน Main Thread ซึ่งเป็น Thread ที่จะทำงานใน onNext() ข้อดีขคือ ไม่ต้องไปเขียน code สำหรับแสดงข้อมูลบน View ด้วยการใช้ method runOnUIThread() เองอีกต่อไปนะ ง่ายขึ้นเยอะ !!
เมื่อ Rx เกิดมาเพื่อช่วยปัญหา แต่ตัวมันเองก็มีปัญหาเช่นกัน
ปัญหาที่เจอบ่อย ๆ คือ ใช้งานได้แต่ไม่เข้าใจ รู้เพียงว่าใช้งานแบบนี้แหละนะ รวมทั้งมี learning curve สูงพอสมควร เนื่องจากมันเปลี่ยนวิธีการคิดสำหรับแก้ไขปัญหา ที่สำคัญ Rx ยังมี operation ต่าง ๆ มากมายให้ใช้งานดังนั้นก่อนจะนำไปใช้งานควรศึกษาและทำความเข้าใจก่อนนะมีอีกปัญหาหนึ่งคือ การแก้ไขปัญหาหนึ่ง ๆ ด้วย Rx นั้น มีหลากหลายวิธีการ รวมทั้งวิธีการแก้ไขปัญหามันขึ้นอยู่กับระบบของเราอีกด้วย ทำให้ยากต่อการศึกษาและนำไปใช้งานอย่างมาก