Key Highlights:
- Flutter เป็น UI toolkit ที่ถูกพัฒนาโดย Google โดย Flutter นั้นใช้ภาษา Dart (ที่ถูกพัฒนาโดย Google เช่นกัน) ในการเขียน และสามารถทำ Cross Platform ได้
- Flutter มี Engine เป็นของตัวเอง ทำให้ไม่มีคอขวด และ Error ที่เกิดจากการ Runtime Compile เหมือน React Native
ว่าแล้วไม่ให้เสียเวลาเรามาเริ่มกันเลยค่ะ Flutter คืออะไร ในช่วง 2 – 3 ปีนี้เรามักได้ยินคนพูดถึง Flutter กันมากขึ้น นั่นเพราะ Flutter เป็น UI toolkit ที่ถูกพัฒนาโดย Google โดย Flutter นั้นใช้ภาษา Dart (ที่ถูกพัฒนาโดย Google เช่นกัน) ในการเขียน
Flutter นั้นสามารถ Complies ได้ทั้ง Mobile (IOS & Android), Web, Embedded, Desktop (ยังเป็น beta อยู่นะ) เราจะเห็นได้ว่าเราสามารถ Develop โค้ดเพียงครั้งเดียวแต่สามารถ Compile ได้หลาย Platform (เราเรียกว่า Hybrid Application คือการพัฒนาแอพแบบ Cross Platfrom) ทำให้เราสามารถประหยัดเวลาในการ Develop แต่ละ Platform ไปได้เยอะ
What’s Cross Platform ?
การพัฒนาแอพแบบ Cross Platform นั้นมีมานานแล้ว ยกตัวอย่างเช่น React Native, Ionic ฯลฯ ถ้าเราสามารถเขียนโค้ดเพียงครั้งเดียวแล้วสามารถ Complie ได้หลาย Platform แล้วทำไมเราถึงไม่ทำ Cross Platform ให้หมดเลยล่ะ
Advantages and Disadvantages with Cross Platform ?
ข้อดีข้อเสียในการทำ Cross Platform มีอะไรบ้าง ในที่นี้ขอยกตัวอย่างเป็น React Native นะคะ ซึ่งในแต่ละ Cross Platform ก็จะมีข้อดีขข้อเสียต่างกันนะ โอเคเราไปดูกันเลย
ข้อดีของการทำ Cross Platform
- Single Codebase ลดเวลาในการ develop และรวมถึงการ test
- ลดระยะเวลาในการเรียนรู้หลายภาษา เพราะในแต่ละ Platform ก็ใช้คนละภาษากัน เช่น Android: Java, IOS: Swift, Web: Javascript & HTML & Css
ข้อเสียของการทำ Cross Platform
- ประสิทธิภาพในการทำงานนั้นน้อยกว่าการทำ Native Application
- โค้ดมีความซับซ้อนมากกว่า เนื่องจากบางครั้งเราจึงต้อง Customize เพื่อให้โค้ดของเราสามารถทำงานได้ทุกแพลฟอร์ม
- Debug ยาก (ทำไมถึง Debug ยาก ขอกล่าวถึงในตอนหลังนะคะ)
จากข้อดีและข้อเสียทั้งหมดทำให้ในการเลือกพัฒนา Application จึงต้องคำนึงถึงข้อจำกัดในการ Customize ของการทำ Hybide ด้วย แล้วบางครั้งเราจึงต้องเลือกการพัฒนาเป็น Native แทน เป็นเหตุให้การทำ Cross Platform นั้นจึงยังไม่เป็นที่นิยมเท่าไหร่ แล้วทำไม Flutter ถึงเริ่มดังขึ้นมาล่ะ Flutter นั้นดีกว่า Hybide ตัวอื่นยังไง เราไปดูกันเลยค่ะ (ใน Blog นี้ของเปรียบเทียบกับ React Native เป็นหลักนะคะ เพราะเรามาจากสาย React Native นะคะ)
React Native vs Flutter
ทำไมเราถึงเลือก React Native เพราะว่าเนื่องจากตอนนั้นเรามาจาก Web ที่ทำด้วย React และจำเป็นต้อง Develop Mobile Application ทั้ง IOS & Android ด้วยเวลาที่จำกัดทำให้เราไม่สามารถเรียนรู้ทั้ง Swift และ Java ได้ทั้งหมด React Native จึงเป็นตัวเลือกแรกๆ ที่เรานึกถึง หลังจากที่เราพัฒนาไปได้สักพักจึงค้นพบว่าเมื่อเกิด Error แล้ว React Native นั้นค่อยข้าง Debug ยาก แล้วทำไมมันถึง Debug ยากล่ะ เราลองไปดูการทำงานของ React Native กันดีกว่าค่ะ
การทำงานของ React Native และ Flutter
การทำงานคร่าวๆของ React Native เกิดเมื่อมี Event กดปุ่มขึ้นมา Platform นั้นต้องแปลง Native Code ผ่าน Bridge (เนื่องจาก React นั้นไม่สามารถ Complie เป็น Native Code ได้จึงมี Bridge เพื่อทำหน้าที่แปลงโค้ดจาก Native -> Javascript หรือจาก Javascript->Native) เพื่อให้ Javascript ของเรานั้นทำการคำนวณต่างๆ แล้วแปลงโค้ดที่ได้ ผ่าน Bridge เป็น Native แล้ว Render ออกมา นั้นจึงทำให้ React Native นั้นมีปัญหาที่เรามักจะพบคือ คอขวดที่เกิดจาก Bridge และ Error ที่เกิดขึ้นตอน Runtime Complie
ในส่วนของ Flutter ในการทำงานนั้น Flutter จะทำการติดต่อกับตัว Hardward ต่างๆได้โดยตรง โดยใน Flutter นั้นมี Engine ของตัวเองส่วนใหญ่ถูกเขียนด้วย C/C++ ทำให้สามารถติดต่อกับตัว Native ได้โดยตรง ไม่ต้องมี Bridge เป็นตัวกลาง เหมือน React Native นั่นเอง
Flutter Architecture Mobile
- Material and Cupertino นั้นเป็นองค์ประกอบพื้นฐาน Interface ที่ Flutter มีมาให้ (เหมือน CSS Framework ใน Web นั่นเอง)
- Widgets นั้นเป็นองค์ประกอบสำคัญในการทำ Interface (Widgets คืออะไรเราจะพูดถึงในหัวข้อถัดไปนะคะ)
- Render Build Tree of Renderable Objects และ Tree สามารถอัปเดต Tree โดยอัตโนมัติ เมื่อ Layout มีการเปลี่ยนแปลง
- Painting เป็นการ Paint หรือระบายภาพ e.g. Shadow, Border
- Gestures เป็นการทำ Interaction e.g. Click
- Foundation นั้นจะ Build ตัว Animation, Painting, และ Gestures
Rendering and layout
ก่อนที่จะอธิบายกา Render ใน Flutter ขอพูดเกี่ยวกับ Widget กันก่อนนะคะว่ามันคืออะไร ทำไมใครๆก็พูดถึงกันก่อนค่ะ
What’s Widget ?
สำหรับใครที่เคยลองเล่น Flutter มาแล้วบ้างคงจะเกิดคำถามขึ้นว่า Widget คืออะไรล่ะ ? Widget ใน Flutter คือการรวมรวมองค์ประกอบแต่ละองค์ประกอบเข้าด้วยกันเพื่อสร้าง User Interface (UI) ขึ้นมา โดย Widget นั้นได้ Inspired มาจาก React Framework โดยมอง Widget เป็น Tree ในการ Render Dart จะ Convert State เป็น UI ผ่าน Method Build และถูก Compile ไปเป็น Native Code แล้วใช้ Skia (Graghic engin: https://skia.org/) ในการ Render ใน Method Build จะมี BuildContext ใช้สำหรับเก็บ Reference ถึง Widget ที่อยู่ในโครงสร้าง Tree
Widget Type
- Stateless Widget คือ Widget ที่ไม่ต้องมีการเปลี่ยนแปลงของ State ใช้เมื่อเราต้องการสร้าง Widget แบบคงที่
- Stateful Widget คือ Widgetที่มีการเปลี่ยนแปลงของ State โดยใช้ setState() เพื่อเปลี่ยนแปลงค่าใน State
Overview render
จากภาพในเป็นการอธิบายการ render โดยเมื่อ User กดช่อง Input จะทำการ Trigger Animation แล้วทำการ Build Widget วางองค์ประกอบต่างๆ แล้วแปลงเป็นภาพใน Screen และทำการรวมองค์ประกอบต่างๆ แล้วส่งต่อไปให้ GPU ทำการแสดงผลโดยมอง Widget เป็น Tree ในการ Render Dart จะ Convert State เป็น UI ผ่าน Method Build และถูก Compile ไปเป็น Native Code แล้วใช้ Skia (Graghic engin: https://skia.org/) ในการ Render ใน Method Build จะมี BuildContext ใช้สำหรับเก็บ Reference ถึง Widget ที่อยู่ในโครงสร้าง Tree
Example Widget Code
เรามาดูตัวอย่างการเขียน Widget กัน
จากโค้ดด้านบนอธิบายด้วยรูปด้านล่างเป็นดังนี้
ในแต่ละรูปเรียงจากซ้ายไปขวาอธิบายได้ดังนี้
- Widget Tree จะมองว่า ใน Container เป็น Parent ที่มี Child เป็น Row และใน Row มี Children เป็น Image และ Text
- Container เป็น ComponentElement ที่มี Row เป็น RenderObjectElement, Image เป็น ComponentElement ที่มี RawImage เป็น RenderObjectElement และมี Text เป็น ComponentElement ที่มี RichText เป็น RenderObjectElement
จากการทำงานด้านบนอ่านแล้วอาจจะยังไม่ค่อยเข้าใจว่าแต่ละอันคืออะไร ขออธิบายความเพิ่มเติมนิดนึงนะคะ
- RenderObject นั้นเป็น Core หลักในการ Render และเป็น Abstract Model สำหรับ Layout และ Painting เพื่อมองให้เห็นภาพมากขึ้นจะยกตัวอย่าประเภทต่างๆของ RenderObject มาอธิบายเพิ่มเติมเช่น RenderParagraph เอาไว้ Render Text, RenderImage เอาไว Renders Image, และ RenderFlex เอาไว้แสดง Children ในรูปแบบ array 1 มิติ
- RenderObjectElement นั้นเป็น Config ต่างๆ เพื่อให้ RenderObject แสดงผล ยกตัวอย่างเช่น การจัดวาง, การกำหนดสีต่างๆ
- ComponentElement คือ Element ที่ประกอบไปด้วย Element ต่างๆ โดยที่ ComponentElement นั้นจะไม่สร้าง RenderObject ตรงๆแต่สร้าง RenderObject ผ่านองค์ประกอบอื่นๆ ตรงกันข้างกับ RenderObjectElement ยกตัวอย่างเช่น Widget Container นั้นจะสร้าง RenderObject ผ่าน Child ที่เป็น RenderObjectElement นั้นเอง
Native (iOS & Android) vs Flutter
แล้วทำไมเราควรจะเลือกอะไรระหว่างเขียนภาษาที่เป็น Native ไปเลยกับ Cross Platform อย่าง Flutter ล่ะ อันนี้ในมุมของผู้เขียนคิดว่าเลือกให้เหมาะสมกับงานที่ต้องการจะทำโดยอิงจากปัจจัย หลายๆอย่างประกอบกันเพื่อหาตัวเลือกที่เหมาะสมที่สุดดีกว่า แน่นอนว่าถ้าเราต้องการที่จะทำแอพทั้ง iOS และ Android โดยที่มีเวลาจำกัดและคนจำกัด แน่นอนว่า Cross Platform คงเหมาะสมที่สุด หรือถ้าเราต้องการ Customize UI เยอะๆใช้ Hardware ของ Device เยอะๆ ต้องการ Performance มากๆ Native อาจจะเป็นตัวเลือกที่ดีกว่า เนื่องจากด้วย Flutter นั้น Community ยังน้อย Package ต่างๆยังมีให้ใช้ไม่เยอะมาก อาจจะไม่มีที่ตรงกับความต้องการของเรา และมีการขยับเวอร์ชั่นค่อนข้างเร็ว อาจจะมีผลกระทบค่อนข้างเยอะ ทั้งนี้ทั้งนั้นไม่ว่าจะเลือกแบบไหนนั้นก็ไม่มีผิดหรือถูกขึ้นกับเราเลือกสิ่งที่เมาหะที่สุดกับงานนั้นๆมาทำนั่นเอง
สุดท้ายนี้ ถ้าหากผู้เขียนอธิบายผิดพลาดประการใด ขออภัยมา ณ ที่นี้ด้วยนะคะ จะคอนเม้นต์ติชม หรืออยากให้เพิ่มเติมอะไรบอกได้เลยนะคะ ขอบคุณค่ะ
HAPPY CODING & Have a nice day ka :)
Reference:
https://docs.flutter.dev/resources/architectural-overview
https://www.cuelogic.com/blog/flutter-vs-react-native-a-comparison-based-on-criteria
A special thank you to K'Theeraporn T. for their invaluable contribution to this blog.