การพัฒนา 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
โดยแต่ละตัวนั้น มีรูปแบบการทำงานและใช้งานที่แตกต่างกัน
รวมทั้งมีข้อจำกัดต่าง ๆ อีกด้วย
เช่น AsyncTask นั้นก็ให้เกิด
callback hell ได้
เมื่อต้องจัดการ flow การทำงานที่ซับซ้อน
หรือมีลำดับการทำงานเยอะ
การจัดการ error ต่าง ๆ ก็ยาก แต่ทำได้นะ ใช้ความสามารถนิดหน่อย
เขียน code เพิ่มมาอีกเยอะพอสมควร
ต้องลงแรงเสียเวลาเขียน code มาจัดการเรื่องต่าง ๆ เองทั้ง
- จัดการ 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() ทำงานสำเร็จและนำผลการทำงานมาใช้งาน จากตัวอย่างคือรายชื่อของเพื่อนนั่นเอง
[gist id="f00f63170493ef4fcd52512f8ba60e0b" file="11.java"]
ปล. 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() เองอีกต่อไปนะ ง่ายขึ้นเยอะ !!
[gist id="f00f63170493ef4fcd52512f8ba60e0b" file="22.java"]
ที่สำคัญมาก ๆ คือ เมื่อ Activity ถูกทำลายแล้ว ต้องทำการ unsubscribe ด้วยนะ
มิเช่นนั้นอาจจะเกิดปัญหา memory leak ได้
[gist id="f00f63170493ef4fcd52512f8ba60e0b" file="23.java"]
ดูเหมือนง่าย ๆ นะ แต่เมื่อนำมาใช้งานจริง ๆ
เจอปัญหาและเหตุการณ์ต่าง ๆ
จะพบว่า เราต้องเรียนรู้เพิ่มอีกมากมาย
แต่มันคือสิ่งที่ developer ที่ดีต้องทำนะ
เมื่อ Rx เกิดมาเพื่อช่วยปัญหา แต่ตัวมันเองก็มีปัญหาเช่นกัน
ปัญหาที่เจอบ่อย ๆ คือ ใช้งานได้แต่ไม่เข้าใจ
รู้เพียงว่าใช้งานแบบนี้แหละนะ
รวมทั้งมี learning curve สูงพอสมควร
เนื่องจากมันเปลี่ยนวิธีการคิดสำหรับแก้ไขปัญหา
ที่สำคัญ Rx ยังมี operation ต่าง ๆ มากมายให้ใช้งาน
ดังนั้นก่อนจะนำไปใช้งานควรศึกษาและทำความเข้าใจก่อนนะ
มีอีกปัญหาหนึ่งคือ การแก้ไขปัญหาหนึ่ง ๆ ด้วย Rx นั้น มีหลากหลายวิธีการ
รวมทั้งวิธีการแก้ไขปัญหามันขึ้นอยู่กับระบบของเราอีกด้วย
ทำให้ยากต่อการศึกษาและนำไปใช้งานอย่างมาก
สุดท้ายแล้ว
ก่อนจะนำอะไรมาใช้งานต้องเรียนรู้และทำความเข้าใจให้ดีก่อน
ดังนั้นให้เวลาบ้าง อย่านำมาใช้เพราะเขาบอกว่าดี
พิจารณาไปที่ระบบงานด้วยว่าเหมาะสมหรือไม่ ?
ที่สำคัญสำหรับ Android app ยิ่งนำ library มาใช้มาก
ก็ยิ่งทำให้เกิดปัญหา
64K ได้ง่ายนะครับ
Source code ตัวอย่างอยู่ที่
Github::Up1:Learn Reactive Android