22 ตุลาคม 2557

[Android Code] Fragment Principle - มารู้จักกับ Fragment กันเถอะ~



        ในที่สุดก็ถึงเวลาที่ต้องทำบทความนี้กันเสียที ซึ่ง Fragment ถือว่าเป็นเรื่องที่ค่อนข้างใหญ่มากๆในการเขียนแอพฯแอนดรอยด์ และเจ้าของบล็อกก็เชื่อว่าผู้ที่หลงเข้ามาอ่านคงจะเคยได้ยินหรือรู้จักกันอยู่แล้ว แต่ Fragment ก็เป็นเรื่องที่ยากจะเข้าใจและยากที่จะใช้งานด้วยเช่นกัน

        เจ้าของบล็อกก็เล็งบทความ Fragment มานมนานแล้ว แต่ทว่าการคิดเนื้อหาสำหรับเรื่องนี้ก็ยากเช่นกัน ไม่รู้ว่าจะเริ่มอธิบายยังไงดี อธิบายเรื่องอะไรบ้าง และตัวอย่างไหนดี แต่ในตอนนี้ก็ถึงคราวฤกษ์งามยามดีแล้ว ก็ขอเริ่มจากแนะนำให้รู้จักกันก่อนว่า Fragment คืออะไรและมีไว้ทำอะไร

        Fragment นั้นถูกนำเสนอขึ้นมาตั้งแต่ Android 3.0 Honeycomb ซึ่งเป็นยุคเริ่มต้นของ Android Tablet ที่มีหน้าจอขนาดใหญ่ขึ้น การใช้งานแตกต่างไปจาก Phone ดังนั้นในการออกแบบ UI แบบเดิมๆที่เคยมีอยู่ก็จะเปลี่ยนแปลงไปสิ้นเชิง

        เวลาเขียนแอพฯบน Phone แบบมีหลายหน้าก็ทำ Activity หลายๆ Activity โดยให้แต่ละหน้าแสดงต่างกันไปตามต้องการ



        และเมื่อมี Tablet ขึ้นมา วิธีที่ทำอยู่เช่นนี้ก็ยังคงใช้งานได้เหมือนเดิมนะ



        ดังนั้นจึงมีนักพัฒนาหลายๆคนที่ใช้วิธี Scale จากหน้าจอแบบ Phone ให้พอดีกับแบบ Tablet แทน เพื่อที่ว่าจะได้ไม่ต้องแก้อะไรมาก



        แต่เอาเข้าจริง การทำแบบนี้มันถูกต้องแล้วหรือ?

        ถึงแม้จะแก้ปัญหาเรื่องหน้าจอได้แต่ทว่าก็ไม่ใช่วิธีที่ถูกต้องซักเท่าไร เพราะยิ่ง Scale ให้ใหญ่ขึ้น UI ก็จะมีขนาดใหญ่ตาม จึงเกิดพื้นที่ไร้ประโยชน์เยอะมาก เหมือนมีพื้นที่ร้อยเอเคอร์แต่ปลูกต้นไม้แค่สองเอเคอร์ยังไงยังงั้น แถม User ต้องขยับนิ้วไปมาบนหน้าจอไกลขึ้นกว่าเดิม



        ดังนั้นเพื่อให้เกิดประโยชน์สูงสุดสำหรับ Tablet จึงต้องเปลี่ยนวิธีดีไซน์หน้าตาของแอพฯให้เหมาะสมกับแต่ละอุปกรณ์ยิ่งขึ้น (เป็นที่มาของคำว่า Fragmentation นั่นเอง) โดยที่สร้างแอพฯแค่ตัวเดียว แต่รันได้บนอุปกรณ์ทุกๆแบบ ไม่ต้องมานั่งทำเป็น For Tablet หรือ For Phone แยกกัน

        โดยแนวคิดนี้จะสมมติตัวอย่างง่ายๆว่า แอพฯโดยพื้นฐานจะมีหน้าเมนูหลักที่กดแล้วจะไปแต่ละหน้าย่อย



        และเมื่อแสดงบน Tablet ก็จะใช้ประโยชน์จากพื้นที่ที่มีเยอะโดยแทรกเมนูไว้ที่ซ้ายมือของหน้าจอไปเลย แล้วแต่ละหน้าก็แสดงผลที่ฝั่งขวามือแทน


        ซึ่งวิธีนี้เรียกว่า Multi-pane UI โดยจะช่วยให้ใช้ประโยชน์จากพื้นที่ในอุปกรณ์แต่ละแบบได้อย่างมีประสิทธิภาพมากขึ้น แต่ถึงกระนั้นก็ต้องทำในแต่ละหน้าให้ Flexible UI อยู่ดีนะ


        แล้วจะทำยังไงล่ะ?

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



        เงื่อนไขคือแอพฯตัวนั้นต้องรองรับทั้งแบบ Tablet และ Phone ตามที่วางไว้ ดังนั้นดูภาพตัวอย่างข้างบนแล้วนึกภาพตามคร่าวๆเลย ว่าถ้าจะต้องมานั่งเขียน Activity หนึ่งตัว ให้ Manage สองแบบ โดยเช็คว่าเป็น Tablet หรือ Phone แล้วค่อยดึง Layout แยกกัน และใช้คำสั่งต่างกัน

        แค่นึกก็ท้อแล้วใช่มั้ยล่ะ? นี่ยังไม่รวมว่ามีหลายๆหน้าอีกด้วยนะ

        แต่เอาเข้าจริงก็มีผู้ที่หลงเข้ามาอ่านที่ใช้วิธีสร้าง Layout ให้มีแถบ Menu ทุกๆหน้าซะเลย แล้วมองว่าเป็น Activity ปกติ เวลาเปลี่ยนหน้าก็ใช้ Intent เหมือนเดิม


        แต่วิธีนี้ก็ไม่ถูกต้องเช่นกัน เพราะว่าต้อง Duplicated คำสั่งของเมนูไว้ที่ทุกๆ Activity กลายเป็นว่าโค๊ดเกิดความซับซ้อนเองซะงั้น (ถ้าแก้โค๊ดของเมนู ก็ต้องมานั่งไล่เปลี่ยนของทุกๆ Activity ด้วย) และเวลาเปลี่ยนหน้าก็จะเกิด Transition ไปทั้งหน้าจอด้วย ซึ่งดูไม่ค่อย Make Sense ซักเท่าไร


        ดังนั้นจึงเลิกคิดที่จะเอา Activity มาทำแบบลวกๆได้เลย


        อีกวิธีที่มีผู้ที่หลงเข้ามาอ่านหลายๆคนใช้อยู่ คือ TabActivity ซึ่งเป็น Activity ที่ใช้งานร่วมกับ Tab Host เพื่อแสดง Activity ย่อยไว้ใน Activity อีกทีหนึ่ง

        ข้อดีคือ Activity ถูกแยกเป็นสัดส่วนเรียบร้อยแล้ว โค๊ดสำหรับหน้านั้นๆก็อยู่ที่ Activity ย่อย ส่วนหน้าเมนูก็อยู่ใน TabActivity ไปเลย ดังนั้นเวลากดเลือกเมนูใดๆใน TabActivity ก็จะเป็นการสั่งเปลี่ยน Activity ที่แสดงนั่นเอง



        แต่ทว่า TabActivity ก็เกิดมาในสมัยที่มีแต่ Phone เท่านั้น ซึ่งไม่ได้รองรับกับปํญหา Fragmentation ในเรื่องของหน้าจอซักเท่าไร อีกทั้งยังมีปัญหาในเรื่องของ Complicated เนื่องจาก Activity มีการทำงานที่ซ้อนกัน รวมไปถึงปัญหาการส่งข้อมูลระหว่าง Activity ก็ยังทำได้ไม่ค่อยดีนัก (เช่น อยากจะกดปุ่มใน Activity แรก แล้วแสดงผลใน Activity ที่สอง)


        แล้วมันทำได้มั้ย? ทำได้ แต่ไม่สนุกหรอก...แม้แต่การส่งค่ากลับไปยัง TabActivity ก็ตาม


        เนื่องจาก TabActivity ทำขึ้นมาเพื่อให้ Activity ที่อยู่ในนั้นทำงานกันแบบ Separated ซะมากกว่า ดังนั้นแต่ละส่วนจึงทำงานร่วมกันได้ค่อนข้างยาก


        ทีม Android ได้เห็นปัญหานี้อยู่แล้วจึงออก Fragment ขึ้นมาเพื่อรองรับการทำงานแบบดังกล่าว เพื่อให้แอพฯสามารถรองรับกับ Fragmentation ของหน้าจอได้ง่ายขึ้น (แต่เอาเข้าจริงก็ยากสำหรับผู้ที่หลงเข้ามาอ่านหลายๆคน) และประกาศให้เลิกใช้งาน TabActivity แล้ว (Deprecated)

        Fragment เรียกได้ว่าเกิดมาเพื่อ Activity เลยก็ว่าได้ แต่ก็ไม่ได้สืบทอดมาจาก Activity แต่อย่างใด โดยที่ Fragment แต่ละตัวสามารถผูกเข้ากับ Layout เพื่อแสดงผลได้ (คล้ายกับ Activity) มี Life Cycle เป็นของตัวเอง (ต่างกับ Activity เล็กน้อย) เพื่อให้ Manage การทำงานใน Fragment นั้นๆได้ โดยมี Activity เพียงตัวเดียวที่คอยควบคุม และที่สำคัญสามารถ Reusable ได้ด้วย



        นี่มันคล้ายกับ List View เลยนี่?

        การทำงานโดยรวมค่อนข้างคล้ายกับ List View แบบที่เคยเข้าใจกันนั่นแหละ แต่ Fragment ที่เป็นอะไรที่ใหญ่กว่า List View มาก ในแง่ของคุณสมบัติและความสามารถ

        ยกตัวอย่างเช่น ต้องการทำ List View ที่แต่ละ Row สามารถแสดงผลได้ 3 รูปแบบ


        จะเห็นว่าการทำงานแทบทุกอย่างของแต่ละ Row จะอยู่ใน getView ทั้งหมด ไม่มี Life Cycle จึงทำให้มีข้อจำกัดในการทำงานค่อนข้างมาก

        แต่สำหรับ Fragment นั้นมีจุดเด่นอยู่ตรงที่สามารถ Extend ได้เรื่อยๆ ดังนั้นจึงสร้าง Fragment แต่ละตัวให้ทำงานต่างกันได้เต็มที่ แถมมี Life Cycle ที่จะช่วยให้ Manage การทำงานหลายๆอย่างได้สะดวกขึ้น



        มันก็เหมือนกับ Activity เลยนี่ แล้วมันต่างจาก Activity ยังไง?

        อย่างที่บอกไปว่า Fragment เป็นแค่ Sub เท่านั้น โดยมีการทำงานหลักอยู่ที่ Activity ดังนั้นใน Fragment ก็จะไม่มีคำสั่งบางอย่างที่ไปขัดกับ Activity เช่น onBackPressed, onActivityResult และ startActivity เป็นต้น

        และ Fragment นั้นๆก็สามารถเรียกย้อนกลับไปยัง Activity ของตัวเองได้ เช่น อยากให้ทำคำสั่งบางอย่างของ Activity ก็เรียก Activity นั้นๆใน Fragment แล้วเรียก Methods ที่อยู่ใน Activity ได้ทันที


        ทั้งนี้เพื่อไม่ให้เกิด Complicated ใน Main Operation นั่นเอง ตามที่บอกในตอนแรกว่า Fragment จะทำคำสั่งตามหน้าที่ของตนเอง ส่วนการทำงานโดยรวมจะให้ Activity เป็นตัวควบคุม

        และการทำงานโดยรวมที่ว่าของ Activity ที่รวมไปถึงการควบคุม Fragment ที่จะแสดงด้วย ว่าจะให้ Fragment มีลำดับอย่างไร ซึ่งตรงนี้ช่วยให้ Fragment นั้นสามารถ Reusable ได้ และกำหนด Fragment ที่จะแสดงได้ รวมไปถึง Transition และการรับส่งข้อมูลระหว่าง Fragment - Fragment หรือ Activity - Fragment



        อยากจะทำมากกว่า 1 ชุดก็ได้นะ



        ณ จุดนี้ขอทำความเข้าใจก่อนนะว่า Fragment ไม่จำเป็นต้องมีมากกว่า 1 หรือแสดงแบบ List เสมอไปนะ เพียงแค่ว่ามันยกตัวอย่างแล้วเห็นภาพได้เข้าใจง่ายดี ถ้าจะใช้งานแค่ Fragment ตัวเดียวก็ทำได้เช่นกัน อย่างเช่น Google Maps API นั่นเอง ถ้าผู้ที่หลงเข้ามาอ่านคนใดเคยใช้ก็จะสังเกตเห็นว่าเวลาสร้าง Layout จะใช้เป็น Fragment



        ที่ Google Maps API ทำเป็น Fragment ก็เพราะว่าเผื่อนักพัฒนาที่นำไปใช้งานร่วมกับ Fragment ตัวอื่นๆนั่นเอง ดังนั้นถ้าใช้กับ Activity โดยตรงก็ทำได้ และถ้าใช้ร่วมกับ Fragment ตัวอื่นๆก็ทำได้เช่นกัน


        จึงเป็นสาเหตุที่ว่าไลบรารีที่เป็น View หลายๆตัวนั้นรองรับการทำงานบน Fragment

        โดยที่ Fragment นั้นจะมีสองแบบคือ API แบบที่มากับ Android 3.0 Honeycomb และแบบที่เป็น Android Support Library v4 เพื่อให้สามารถทำงานบนแอนดรอยด์เวอร์ชันเก่าๆได้

        • android.app.Fragment
        • android.support.v4.app.Fragment

        สำหรับ API ที่มากับ Android 3.0 Honeycomb นั้นไม่ค่อยนิยมใช้กันซักเท่าไรและนักพัฒนาส่วนใหญ่ก็หันมาใช้ของ Android Support Library v4 แทน ดังนั้นในบทความของเจ้าของบล็อกก็จะใช้เป็นตัว Android Support Library v4 แทนเช่นกัน แต่เดี๋ยวก็พูดถึงการใช้ Fragment API เดิมให้ด้วย เพราะว่าทั้งสองมีการใช้งานที่ต่างกันนิดหน่อย

        อ๊ะๆ อยากอ่านต่อแล้วล่ะสิ แต่ต้องขอจบ Fragment Principle เพียงเท่านี้ก่อน เพราะรู้สึกว่ายิ่งพิมพ์ก็ยิ่งเพลิน ตอนแรกๆไม่ได้ตั้งใจจะทำเยอะขนาดนี้นะเนี่ย ฮ่าๆ ดังนั้นขอเบรกก่อนว่าจะเอา Fragment มาทำ Multi-pane UI ได้อย่างไรนะครับ


        อดใจรอหน่อยนะ เพราะบทความนี้กินพลังงานเยอะมาก



บทความที่เกี่ยวข้อง

        • Fragment Principle - มารู้จักกับ Fragment กันเถอะ~
        • Let's Fragment - เริ่มต้นง่ายๆกับ Fragment แบบพื้นฐาน
        • Let's Fragment - รู้จักกับ FragmentTransaction สำหรับการแสดง Fragment [ตอนที่ 2]
        • Let's Fragment - มาทำ View Pager กันเถิดพี่น้อง~ [ตอนที่ 1]
        • Let's Fragment - มาทำ View Pager กันเถิดพี่น้อง~ [ตอนที่ 2]




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium