react-channel-image
การพัฒนา 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 ที่แย่มาก ๆ

anr

บางครั้งอาจจะแก้ไขปัญหาแบบแก้ผ้าเอาหน้ารอดไปก่อนเช่น
แสดง 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)

ปล. การทำงานจะไม่รอจนการ 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
ดังนี้

จากนั้นทำการ subscribe ซะ
และต้องกำหนด property ในการเรียกใช้เพิ่มนิดหน่อยดังนี้

  • subscribeOn() จากตัวอย่างเป็นการ subscribe บน I/O Thread
  • observerOn() จากตัวอย่างเป็นการ observer บน Main Thread ซึ่งเป็น Thread ที่จะทำงานใน onNext() ข้อดีขคือ ไม่ต้องไปเขียน code สำหรับแสดงข้อมูลบน View ด้วยการใช้ method runOnUIThread() เองอีกต่อไปนะ ง่ายขึ้นเยอะ !!

ที่สำคัญมาก ๆ คือ เมื่อ Activity ถูกทำลายแล้ว ต้องทำการ unsubscribe ด้วยนะ
มิเช่นนั้นอาจจะเกิดปัญหา memory leak ได้

ดูเหมือนง่าย ๆ นะ แต่เมื่อนำมาใช้งานจริง ๆ
เจอปัญหาและเหตุการณ์ต่าง ๆ
จะพบว่า เราต้องเรียนรู้เพิ่มอีกมากมาย
แต่มันคือสิ่งที่ developer ที่ดีต้องทำนะ

เมื่อ Rx เกิดมาเพื่อช่วยปัญหา แต่ตัวมันเองก็มีปัญหาเช่นกัน

ปัญหาที่เจอบ่อย ๆ คือ ใช้งานได้แต่ไม่เข้าใจ
รู้เพียงว่าใช้งานแบบนี้แหละนะ
รวมทั้งมี learning curve สูงพอสมควร
เนื่องจากมันเปลี่ยนวิธีการคิดสำหรับแก้ไขปัญหา
ที่สำคัญ Rx ยังมี operation ต่าง ๆ มากมายให้ใช้งาน

ดังนั้นก่อนจะนำไปใช้งานควรศึกษาและทำความเข้าใจก่อนนะ

มีอีกปัญหาหนึ่งคือ การแก้ไขปัญหาหนึ่ง ๆ ด้วย Rx นั้น มีหลากหลายวิธีการ
รวมทั้งวิธีการแก้ไขปัญหามันขึ้นอยู่กับระบบของเราอีกด้วย
ทำให้ยากต่อการศึกษาและนำไปใช้งานอย่างมาก

สุดท้ายแล้ว

ก่อนจะนำอะไรมาใช้งานต้องเรียนรู้และทำความเข้าใจให้ดีก่อน
ดังนั้นให้เวลาบ้าง อย่านำมาใช้เพราะเขาบอกว่าดี
พิจารณาไปที่ระบบงานด้วยว่าเหมาะสมหรือไม่ ?

ที่สำคัญสำหรับ Android app ยิ่งนำ library มาใช้มาก
ก็ยิ่งทำให้เกิดปัญหา 64K ได้ง่ายนะครับ

Source code ตัวอย่างอยู่ที่ Github::Up1:Learn Reactive Android