Quantcast
Channel: cc :: somkiat
Viewing all articles
Browse latest Browse all 2036

ว่าด้วยเรื่อง Asynchronous สำหรับ Android

$
0
0

react-channel-image

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) [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

Viewing all articles
Browse latest Browse all 2036

Trending Articles