ในช่วงหลายปีที่ผ่านมาฉันได้เห็นการใช้งานรูปแบบการนำทางที่แตกต่างกันมากมายใน Android แอปบางแอปใช้เฉพาะกิจกรรมในขณะที่กิจกรรมอื่น ๆ ผสมกับส่วนย่อยและ / หรือด้วยมุมมองที่กำหนดเอง
หนึ่งในการใช้งานรูปแบบการนำทางที่ฉันชื่นชอบนั้นอิงตามปรัชญา“ One-Activity-Multiple-Fragments” หรือเพียงแค่รูปแบบการนำทางของ Fragment โดยทุกหน้าจอในแอปพลิเคชันจะเป็น Fragment แบบเต็มหน้าจอและส่วนทั้งหมดหรือส่วนใหญ่จะอยู่ใน หนึ่งกิจกรรม
วิธีนี้ไม่เพียง แต่ทำให้การนำทางไปใช้งานง่ายขึ้นเท่านั้น แต่ยังมีประสิทธิภาพที่ดีขึ้นมากและส่งผลให้ผู้ใช้ได้รับประสบการณ์ที่ดีขึ้น
ในบทความนี้เราจะดูการใช้งานรูปแบบการนำทางทั่วไปใน Android จากนั้นแนะนำรูปแบบการนำทางตาม Fragment โดยเปรียบเทียบและเปรียบเทียบกับรูปแบบอื่น ๆ อัปโหลดแอปพลิเคชันสาธิตที่ใช้รูปแบบนี้แล้ว GitHub .
แอปพลิเคชัน Android ทั่วไปที่ใช้เฉพาะกิจกรรมจะถูกจัดเป็นโครงสร้างแบบต้นไม้ (อย่างแม่นยำมากขึ้นในกราฟกำกับ) ซึ่งตัวเรียกใช้งานเริ่มต้นกิจกรรมรูท ขณะที่คุณนำทางในแอปพลิเคชันจะมีกิจกรรมแบ็กสแต็กที่ดูแลโดย OS
ตัวอย่างง่ายๆแสดงในแผนภาพด้านล่าง:
นักพัฒนาซอฟต์แวร์ไม่ได้ใช้ภาษาโปรแกรมเชิงวัตถุอีกต่อไป
กิจกรรม A1 เป็นจุดเริ่มต้นในแอปพลิเคชันของเรา (ตัวอย่างเช่นแสดงถึงหน้าจอเริ่มต้นหรือเมนูหลัก) และจากนั้นผู้ใช้สามารถไปที่ A2 หรือ A3 ได้ เมื่อคุณต้องการสื่อสารระหว่างกิจกรรมต่างๆคุณสามารถใช้ไฟล์ startActivityForResult () หรือบางทีคุณอาจแบ่งปันวัตถุตรรกะทางธุรกิจที่สามารถเข้าถึงได้ทั่วโลกระหว่างกัน
เมื่อคุณต้องการเพิ่มกิจกรรมใหม่คุณต้องทำตามขั้นตอนต่อไปนี้:
แน่นอนว่าแผนภาพการนำทางนี้เป็นแนวทางที่ค่อนข้างง่าย อาจกลายเป็นเรื่องที่ซับซ้อนมากเมื่อคุณต้องการ จัดการกองหลัง หรือเมื่อคุณต้องใช้กิจกรรมเดิมซ้ำหลาย ๆ ครั้งตัวอย่างเช่นเมื่อคุณต้องการนำทางผู้ใช้ผ่านหน้าจอบทช่วยสอนบางหน้าจอ แต่ในความเป็นจริงแล้วแต่ละหน้าจอใช้กิจกรรมเดียวกันเป็นฐาน
โชคดีที่เรามีเครื่องมือที่เรียกว่า งาน และแนวทางบางประการสำหรับ การนำทางด้านหลังที่เหมาะสม .
จากนั้นด้วย API ระดับ 11 ชิ้นส่วน ...
Android เปิดตัวแฟรกเมนต์ใน Android 3.0 (API ระดับ 11) เพื่อรองรับการออกแบบ UI แบบไดนามิกและยืดหยุ่นมากขึ้นบนหน้าจอขนาดใหญ่เช่นแท็บเล็ต เนื่องจากหน้าจอของแท็บเล็ตมีขนาดใหญ่กว่าโทรศัพท์มือถือมากจึงมีพื้นที่ในการรวมและเปลี่ยนองค์ประกอบ UI ได้มากขึ้น แฟรกเมนต์อนุญาตการออกแบบดังกล่าวโดยไม่จำเป็นให้คุณจัดการการเปลี่ยนแปลงที่ซับซ้อนของลำดับชั้นมุมมอง ด้วยการแบ่งเค้าโครงของกิจกรรมออกเป็นส่วนย่อยคุณจะสามารถแก้ไขลักษณะที่ปรากฏของกิจกรรมในรันไทม์และรักษาการเปลี่ยนแปลงเหล่านั้นไว้ในแบ็กสแต็กที่จัดการโดยกิจกรรมได้ - อ้างจาก Google’s คู่มือ API สำหรับ Fragments .
ของเล่นใหม่นี้อนุญาตให้นักพัฒนาสร้าง UI แบบหลายบานหน้าต่างและนำส่วนประกอบกลับมาใช้ในกิจกรรมอื่น ๆ นักพัฒนาบางคนชอบสิ่งนี้ในขณะที่คนอื่น ๆ ไม่ . เป็นข้อถกเถียงที่ได้รับความนิยมว่าควรใช้ชิ้นส่วนหรือไม่ แต่ฉันคิดว่าทุกคนคงเห็นด้วยว่าชิ้นส่วนมีความซับซ้อนเพิ่มขึ้นและนักพัฒนาจำเป็นต้องทำความเข้าใจจริงๆเพื่อที่จะใช้ชิ้นส่วนเหล่านี้อย่างถูกต้อง
ฉันเริ่มเห็นตัวอย่างมากขึ้นเรื่อย ๆ โดยที่ชิ้นส่วนนั้นไม่ได้เป็นเพียงตัวแทนของส่วนหนึ่งของหน้าจอเท่านั้น แต่ในความเป็นจริงแล้วหน้าจอทั้งหมดเป็นส่วนที่มีอยู่ในกิจกรรม เมื่อฉันได้เห็นการออกแบบที่ทุกกิจกรรมมีส่วนแบบเต็มหน้าจอเพียงชิ้นเดียวและไม่มีอะไรเพิ่มเติมและเหตุผลเดียวที่กิจกรรมเหล่านี้มีอยู่คือการโฮสต์ชิ้นส่วนเหล่านี้ ถัดจากข้อบกพร่องในการออกแบบที่เห็นได้ชัดยังมีปัญหาอีกประการหนึ่งในแนวทางนี้ ดูแผนภาพด้านล่าง:
A1 สื่อสารกับ F1 ได้อย่างไร? Well A1 สามารถควบคุม F1 ได้ทั้งหมดตั้งแต่สร้าง F1 A1 สามารถส่งบันเดิลตัวอย่างเช่นในการสร้าง F1 หรือสามารถเรียกใช้เมธอดสาธารณะได้ F1 สื่อสารกับ A1 ได้อย่างไร? สิ่งนี้ซับซ้อนกว่า แต่สามารถแก้ไขได้ด้วยรูปแบบการโทรกลับ / ผู้สังเกตการณ์ที่ A1 สมัคร F1 และ F1 แจ้ง A1
นั่นอาจเป็นทั้งหมดที่ฉันจำเป็นต้องรู้
แต่ A1 และ A2 สื่อสารกันได้อย่างไร? สิ่งนี้ได้รับการคุ้มครองแล้วเช่นผ่าน startActivityForResult () .
และตอนนี้คำถามที่แท้จริงก็มาถึง: F1 และ F2 สื่อสารกันได้อย่างไร? แม้ในกรณีนี้เราสามารถมีองค์ประกอบตรรกะทางธุรกิจซึ่งมีอยู่ทั่วโลกดังนั้นจึงสามารถใช้เพื่อส่งผ่านข้อมูลได้ แต่สิ่งนี้ไม่ได้นำไปสู่การออกแบบที่หรูหราเสมอไป จะเกิดอะไรขึ้นถ้า F2 ต้องการส่งผ่านข้อมูลบางส่วนไปยัง F1 ด้วยวิธีที่ตรงกว่า ด้วยรูปแบบการโทรกลับ F2 สามารถแจ้ง A2 ได้จากนั้น A2 จะเสร็จสิ้นด้วยผลลัพธ์และผลลัพธ์นี้ถูกจับโดย A1 ซึ่งแจ้ง F1
วิธีนี้ต้องใช้รหัสสำเร็จรูปจำนวนมากและกลายเป็นแหล่งที่มาของข้อบกพร่องความเจ็บปวดและความโกรธอย่างรวดเร็ว
จะเป็นอย่างไรหากเราสามารถกำจัดกิจกรรมทั้งหมดและเก็บไว้เพียงกิจกรรมเดียวซึ่งทำให้ส่วนที่เหลืออยู่?
ความแตกต่างระหว่าง s คอร์ปอเรชั่น กับ คอร์ปอเรชั่น C คืออะไร
ในช่วงหลายปีที่ผ่านมาฉันเริ่มใช้รูปแบบ“ หนึ่งกิจกรรม - หลายชิ้นส่วน” ในแอปพลิเคชันส่วนใหญ่ของฉันและฉันก็ยังใช้มันอยู่ มีการอภิปรายมากมายเกี่ยวกับแนวทางนี้เช่น ที่นี่ และ ที่นี่ . สิ่งที่ฉันพลาดไป แต่เป็นตัวอย่างที่เป็นรูปธรรมซึ่งฉันสามารถดูและทดสอบได้ด้วยตัวเอง
ลองดูแผนภาพต่อไปนี้:
ตอนนี้เรามีกิจกรรมคอนเทนเนอร์เพียงรายการเดียวและเรามีชิ้นส่วนหลายชิ้นซึ่งมีโครงสร้างเหมือนต้นไม้อีกครั้ง การนำทางระหว่างพวกเขาได้รับการจัดการโดย FragmentManager มันมีกองหลัง
สังเกตว่าตอนนี้เราไม่มีไฟล์ startActivityForResult () แต่เราสามารถใช้รูปแบบการโทรกลับ / ผู้สังเกตการณ์ได้ เรามาดูข้อดีข้อเสียของแนวทางนี้กัน:
ตอนนี้เรามีเพียงกิจกรรมเดียวเราไม่จำเป็นต้องอัปเดตรายการทุกครั้งที่เพิ่มหน้าจอใหม่อีกต่อไป ต่างจากกิจกรรมที่เราไม่ต้องประกาศเศษ
สิ่งนี้อาจดูเหมือนเป็นเรื่องเล็กน้อย แต่สำหรับแอปพลิเคชันขนาดใหญ่ที่มีกิจกรรมมากกว่า 50 กิจกรรมสิ่งนี้สามารถปรับปรุงความสามารถในการอ่านไฟล์ AndroidManifest.xml ไฟล์.
ตัวอย่างการรวมสปริงทีละขั้นตอน
ดูไฟล์รายการของแอปพลิเคชันตัวอย่างซึ่งมีหลายหน้าจอ ไฟล์รายการยังคงเรียบง่ายมาก
package='com.exarlabs.android.fragmentnavigationdemo.ui' >
ในตัวอย่างโค้ดของฉันคุณจะเห็นว่าฉันใช้ NavigationManager ซึ่งในกรณีของฉันมันถูกฉีดเข้าไปในทุกส่วน ตัวจัดการนี้สามารถใช้เป็นสถานที่รวมศูนย์สำหรับการบันทึกการจัดการแบ็คสแต็กและอื่น ๆ ดังนั้นพฤติกรรมการนำทางจึงแยกออกจากตรรกะทางธุรกิจที่เหลือและไม่แพร่กระจายไปทั่วในการใช้งานหน้าจอต่างๆ
ลองจินตนาการถึงสถานการณ์ที่เราต้องการเริ่มหน้าจอที่ผู้ใช้สามารถเลือกบางรายการจากรายชื่อบุคคล นอกจากนี้คุณยังต้องการส่งผ่านข้อโต้แย้งในการกรองเช่นอายุและอาชีพและเพศ
ในกรณีของกิจกรรมคุณจะต้องเขียน:
Intent intent = new Intent(); intent.putExtra('age', 40); intent.putExtra('occupation', 'developer'); intent.putExtra('gender', 'female'); startActivityForResult(intent, 100);
จากนั้นคุณต้องกำหนดไฟล์ onActivityResult ด้านล่างและจัดการกับผลลัพธ์
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); }
ปัญหาส่วนตัวของฉันเกี่ยวกับแนวทางนี้คือข้อโต้แย้งเหล่านี้เป็น 'ส่วนเสริม' และไม่บังคับดังนั้นฉันต้องตรวจสอบให้แน่ใจว่ากิจกรรมการรับจัดการกับกรณีต่างๆทั้งหมดเมื่อไม่มีส่วนเกิน ต่อมาเมื่อมีการปรับโครงสร้างใหม่และไม่จำเป็นต้องใช้ 'อายุ' เพิ่มเติมอีกต่อไปฉันต้องค้นหาทุกที่ในโค้ดที่ฉันเริ่มกิจกรรมนี้และตรวจสอบให้แน่ใจว่าสิ่งที่แถมมาทั้งหมดถูกต้อง
นอกจากนี้จะไม่ดีกว่านี้หรือหากผลลัพธ์ (รายชื่อบุคคล) จะมาในรูปแบบของ _List_ และไม่อยู่ในรูปแบบอนุกรมซึ่งจะต้องถูก deserialized
ในกรณีของการนำทางแบบแยกส่วนทุกอย่างจะตรงไปตรงมามากขึ้น สิ่งที่คุณต้องทำคือเขียนวิธีการในไฟล์ NavigationManager เรียกว่า startPersonSelectorFragment () ด้วยอาร์กิวเมนต์ที่จำเป็นและด้วยการเรียกใช้งานกลับ
mNavigationManager.startPersonSelectorFragment(40, 'developer', 'female', new PersonSelectorFragment.OnPersonSelectedListener() { @Override public boolean onPersonsSelected(List selection) { [do something] return false; } });
หรือด้วย RetroLambda
mNavigationManager.startPersonSelectorFragment(40, 'developer', 'female', selection -> [do something]);
ระหว่างกิจกรรมเราสามารถแชร์ได้เฉพาะ Bundle ซึ่งสามารถเก็บข้อมูลดั้งเดิมหรือข้อมูลที่ต่อเนื่องกันได้ ตอนนี้เราสามารถใช้รูปแบบการเรียกกลับด้วยเศษส่วนได้โดยที่ F1 สามารถฟัง F2 ที่ส่งผ่านวัตถุโดยพลการ โปรดดูการใช้งานการเรียกกลับตัวอย่างก่อนหน้านี้ซึ่งส่งคืน _List_
สิ่งนี้จะเห็นได้ชัดเมื่อคุณใช้ลิ้นชักซึ่งมีรายการเมนูตัวอย่าง 5 รายการและในแต่ละหน้าลิ้นชักควรจะแสดงอีกครั้ง
ในกรณีของการนำทางกิจกรรมที่แท้จริงแต่ละหน้าควรขยายและเริ่มต้นลิ้นชักซึ่งแน่นอนว่ามีราคาแพง
ในแผนภาพด้านล่างคุณจะเห็นชิ้นส่วนรูทหลายชิ้น (FR *) ซึ่งเป็นชิ้นส่วนแบบเต็มหน้าจอซึ่งสามารถเข้าถึงได้โดยตรงจากลิ้นชักและยังสามารถเข้าถึงลิ้นชักได้ก็ต่อเมื่อชิ้นส่วนเหล่านี้แสดงขึ้น ทุกสิ่งที่อยู่ทางขวาของเส้นประในแผนภาพจะมีเป็นตัวอย่างของโครงร่างการนำทางโดยพลการ
เว็บไซต์หาคู่อันดับ 1 2015
เนื่องจากกิจกรรมคอนเทนเนอร์มีลิ้นชักเราจึงมีลิ้นชักเพียงชุดเดียวดังนั้นในทุกขั้นตอนการนำทางที่คุณควรมองเห็นลิ้นชัก ไม่ต้องขยายและเริ่มต้นใหม่อีกครั้ง . ยังไม่มั่นใจว่าทั้งหมดนี้ทำงานอย่างไร? ดูแอปพลิเคชันตัวอย่างของฉันซึ่งสาธิตการใช้งานลิ้นชัก
ความกลัวที่ยิ่งใหญ่ที่สุดของฉันคือเสมอถ้าฉันใช้รูปแบบการนำทางแบบแบ่งส่วนในโครงการที่ไหนสักแห่งบนท้องถนนฉันจะพบกับปัญหาที่ไม่คาดฝันซึ่งจะแก้ไขได้ยากเกี่ยวกับความซับซ้อนที่เพิ่มขึ้นของชิ้นส่วนไลบรารีของบุคคลที่สามและระบบปฏิบัติการเวอร์ชันต่างๆ จะเกิดอะไรขึ้นถ้าฉันต้องปรับโครงสร้างทุกอย่างที่ทำไปแล้ว?
แน่นอนฉันต้องแก้ไขปัญหาด้วย เศษที่ซ้อนกัน , ไลบรารีของบุคคลที่สามซึ่งใช้แฟรกเมนต์เช่น ShinobiControls , ViewPagers และ FragmentStatePagerAdapters .
ฉันต้องยอมรับว่าการได้รับประสบการณ์ที่เพียงพอกับชิ้นส่วนเพื่อให้สามารถแก้ปัญหาเหล่านี้เป็นกระบวนการที่ค่อนข้างยาว แต่ในทุกกรณีปัญหาไม่ได้อยู่ที่ปรัชญาไม่ดี แต่ฉันไม่เข้าใจชิ้นส่วนดีพอ บางทีถ้าคุณเข้าใจชิ้นส่วนดีกว่าที่ฉันทำคุณจะไม่พบปัญหาเหล่านี้
สิ่งเดียวที่ฉันสามารถพูดถึงได้ในตอนนี้คือเรายังคงพบปัญหาที่จะแก้ไม่ได้เนื่องจากไม่มีไลบรารีสำหรับผู้ใหญ่ที่แสดงสถานการณ์ที่ซับซ้อนทั้งหมดของแอปพลิเคชันที่ซับซ้อนพร้อมการนำทางตามส่วน
ในบทความนี้เราได้เห็นวิธีอื่นในการนำทางในไฟล์ Android ใบสมัคร เราเปรียบเทียบกับปรัชญาการนำทางแบบดั้งเดิมที่ใช้กิจกรรมและเราได้เห็นเหตุผลที่ดีสองสามประการว่าทำไมจึงเป็นประโยชน์ที่จะใช้มันมากกว่าแนวทางดั้งเดิม
ในกรณีที่คุณยังไม่ได้ดูแอปพลิเคชันสาธิตที่อัปโหลดไป GitHub การนำไปใช้ อย่าลังเลที่จะแยกหรือมีส่วนร่วมกับตัวอย่างที่ดีกว่าซึ่งจะแสดงการใช้งานได้ดีขึ้น
ที่เกี่ยวข้อง: ข้อผิดพลาดทั่วไป 10 อันดับแรกที่นักพัฒนา Android ทำ