FragmentPagerAdapter และ FragmentStatePagerAdapter แตกต่างกันอย่างไร


375

ความแตกต่างระหว่างFragmentPagerAdapterและFragmentStatePagerAdapterคืออะไร?

เกี่ยวกับFragmentPagerAdapterคำแนะนำของ Google พูดว่า:

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

และเกี่ยวกับFragmentStatePagerAdapter:

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

ดังนั้นฉันมีเพียง 3 ชิ้น แต่ทั้งหมดเป็นโมดูลแยกต่างหากที่มีข้อมูลจำนวนมาก

Fragment1จัดการข้อมูลบางส่วน (ซึ่งผู้ใช้ป้อน) และผ่านทางกิจกรรมเข้าซึ่งเป็นเพียงง่ายๆFragment2 นอกจากนี้ยังมีListFragmentFragment3ListFragment

ดังนั้นคำถามของฉันคือ : ฉันควรใช้อะแดปเตอร์ใด FragmentPagerAdapterหรือFragmentStatePagerAdapter?


2
ฉันคิดว่าการมีเพียง 3 แฟรกเมนต์ทำให้คุณสามารถใช้ FragmentPagerAdapter ได้ แท็บสำหรับแฟรกเมนต์เหล่านี้อาจปรากฏพร้อมกันทั้งหมด
IgorGanapolsky

2
โพสต์นี้บันทึกไว้ 5-6 ชั่วโมงของฉันเพราะฉันใช้ Adapter ชนิดผิด
Nantaphop

1
คำตอบสำหรับคำถามนี้ส่งคำถามอีกหนึ่งstackoverflow.com/questions/9156406/…
Piyush Kukadiya

มีFragmentPagerAdapterและFragmentStatePagerAdapterแต่คือFragmentStateAdapterอะไร
the_prole

คำตอบ:


292

อย่างที่เอกสารบอกว่าคิดแบบนี้ หากคุณต้องทำแอปพลิเคชันเช่นเครื่องอ่านหนังสือคุณจะไม่ต้องการโหลดชิ้นส่วนทั้งหมดลงในหน่วยความจำทันที คุณต้องการโหลดและทำลายFragmentsตามที่ผู้ใช้อ่าน FragmentStatePagerAdapterในกรณีนี้คุณจะใช้ หากคุณเพิ่งแสดง 3 แท็บ "" ที่ไม่มีข้อมูลจำนวนมาก (เช่นBitmaps) แสดงว่าFragmentPagerAdapterคุณอาจเหมาะกับคุณ นอกจากนี้โปรดทราบว่าViewPagerโดยค่าเริ่มต้นจะโหลด 3 ส่วนในหน่วยความจำ ครั้งแรกที่AdapterคุณพูดถึงอาจทำลายViewลำดับชั้นและโหลดใหม่เมื่อจำเป็นครั้งที่สองAdapterจะบันทึกสถานะของFragmentและทำลายอย่างสมบูรณ์หากผู้ใช้กลับมาที่หน้านั้นสถานะจะถูกดึง


ฉันมีหลายปุ่มและ TextViews ใน Fragment1 และ ListView ซึ่งสร้างรายการแบบไดนามิกใน Fragment2 และ Fragment3 คุณคิดว่าเป็นความคิดที่ดีหรือไม่ที่จะใช้ FragmentStatePagerAdapter และเก็บข้อมูลทั้งหมดในกิจกรรมส่งผ่านไปยัง Fragments ผ่าน Bundle หรือไม่
AlexMomotov

2
@AlexMomotov Views ในเลย์เอาต์ของ Fragment ไม่มีส่วนเกี่ยวข้องกับทางเลือกของ FragmentStatePagerAdapter คำถามที่นี่คือจำนวนของชิ้นส่วนที่จะได้รับการเพจ
IgorGanapolsky

1
ดังนั้นไม่มีมูลความจริงที่FragmentPagerAdapterจะใช้มัน
Tomasz Mularczyk

3
@Tomasz ข้อได้เปรียบของการFragmentPagerAdapterที่การสลับระหว่างแฟรกเมนต์อาจเร็วกว่ามากเนื่องจากFragmentวัตถุจริงไม่จำเป็นต้องถูกสร้างใหม่ในแต่ละครั้ง ในทางกลับกันสิ่งนี้จะจบลงด้วยการใช้หน่วยความจำมากขึ้นเพื่อเก็บชิ้นส่วนของวัตถุในหน่วยความจำ
Richard Le Mesurier

ฉันมี 3 แท็บ / หน้า (แสดงว่าแต่ละ WebView ก) เพื่อให้มีสินค้าFragmentPagerAdapter อย่างไรก็ตามหน้าสุดท้ายยังคงได้รับการวาดใหม่เมื่อฉันปัดข้ามไปจากหน้าแรก viewPager.setOffscreenPageLimit(2)เพื่อแก้ปัญหานี้ฉันได้ใช้
บ้าน geoengineering

131
  • FragmentPagerAdapterเก็บแฟรกเมนต์ทั้งหมดในหน่วยความจำและสามารถเพิ่มโอเวอร์เฮดของหน่วยความจำได้หากใช้แฟรกเมนต์จำนวน ViewPagerมาก

  • ในทางตรงกันข้ามกับพี่น้องของคุณFragmentStatePagerAdapterเพียงเก็บข้อมูลที่บันทึกไว้ของรัฐชิ้นส่วนและทำลายชิ้นส่วนทั้งหมดเมื่อพวกเขาสูญเสียโฟกัส

  • ดังนั้นFragmentStatePagerAdapterควรใช้เมื่อเราต้องใช้ชิ้นส่วนแบบไดนามิกเช่นชิ้นส่วนที่มีวิดเจ็ตเนื่องจากข้อมูลของพวกเขาอาจถูกเก็บไว้ใน. savedInstanceStateมันจะไม่ส่งผลกระทบต่อประสิทธิภาพแม้ว่าจะมีชิ้นส่วนจำนวนมากก็ตาม

  • ในทางตรงกันข้ามพี่น้องFragmentPagerAdapterควรใช้เมื่อเราต้องการเก็บชิ้นส่วนทั้งหมดในหน่วยความจำ

  • เมื่อฉันบอกว่าชิ้นส่วนทั้งหมดถูกเก็บไว้ในหน่วยความจำหมายความว่าอินสแตนซ์ของมันจะไม่ถูกทำลายและจะสร้างโอเวอร์เฮดของหน่วยความจำ ดังนั้นก็ควรที่จะใช้เฉพาะเมื่อมีจำนวนน้อยชิ้นส่วนสำหรับFragmentPagerAdapterViewPager

  • มันจะดียิ่งขึ้นถ้าเศษชิ้นส่วนเป็นแบบคงที่เนื่องจากจะไม่มีวัตถุจำนวนมากที่จะเก็บอินสแตนซ์

เพื่อรายละเอียดเพิ่มเติม

FragmentStatePagerAdapter:

  • ด้วยFragmentStatePagerAdapterชิ้นส่วนที่ไม่จำเป็นของคุณจะถูกทำลายธุรกรรมมีความมุ่งมั่นที่จะลบส่วนจากกิจกรรมของFragmentManagerคุณอย่างสมบูรณ์

  • สถานะFragmentStatePagerAdapterมาจากความจริงที่ว่ามันจะบันทึกเศษของคุณออกBundleจากsavedInstanceStateเมื่อถูกทำลายเมื่อผู้ใช้นำทางกลับมาชิ้นส่วนใหม่จะถูกกู้คืนโดยใช้สถานะของชิ้นส่วน

FragmentPagerAdapter:

  • โดยการเปรียบเทียบFragmentPagerAdapterไม่ได้ทำอะไรชนิดเมื่อชิ้นส่วนที่ไม่จำเป็นอีกต่อไป FragmentPagerAdapterเรียกร้อง ในการทำธุรกรรมแทนdetach(Fragment)remove(Fragment)

  • การทำลายครั้งนี้เป็นมุมมองของชิ้นส่วน แต่ทิ้งตัวอย่างชิ้นส่วนที่ยังมีชีวิตอยู่ใน. FragmentManagerดังนั้นชิ้นส่วนที่สร้างขึ้นในนั้น FragmentPagerAdapterจะไม่ถูกทำลาย


2
ทำไมคุณถึงมี 2 คำตอบ?
Jared Burrows

ประโยชน์ของการเก็บรักษาแฟรกเมนต์ทั้งหมดในหน่วยความจำคืออะไร
Tomasz Mularczyk

4
@Tomek: ถ้าแฟรกเมนต์ถัดไปถูกอินสแตนซ์แล้ว (เช่น FragmentPagerAdapter) มันจะพร้อมที่จะเรนเดอร์เมื่อคุณปัดไปที่มันดังนั้นแอนิเมชั่นการปัดจะราบรื่นขึ้น ด้วย FragmentStatePagerAdapter อินสแตนซ์แฟรกเมนต์ถัดไปอาจไม่มีอยู่จนกว่าคุณจะกวาดนิ้วไปและถ้าเป็นแฟรกเมนต์ขนาดใหญ่ที่มีราคาแพงในการสร้างคุณอาจเห็นการพูดติดอ่างในภาพเคลื่อนไหว มันเป็นคำถามของประสิทธิภาพเทียบกับการใช้หน่วยความจำ
Dalbergia

1
@ Jared Burrows bcoz one เป็นเพียงAnswerTextซึ่งดีสำหรับคำตอบเล็กและคงที่และอื่น ๆ คือAnswerStateTextซึ่งเป็นคำตอบที่ใหญ่กว่าและมีชีวิตชีวา
Simple Fellow

48

นี่คือวงจรชีวิตการบันทึกของแต่ละแฟรกเมนViewPagerต์ที่มี 4 แฟรกเมนต์และoffscreenPageLimit = 1 (default value)

FragmentStatePagerAdapter

ไปที่ Fragment1 (กิจกรรมการเปิดตัว)

Fragment1: onCreateView
Fragment1: onStart
Fragment2: onCreateView
Fragment2: onStart

ไปที่ Fragment2

Fragment3: onCreateView
Fragment3: onStart

ไปที่ Fragment3

Fragment1: onStop
Fragment1: onDestroyView
Fragment1: onDestroy
Fragment1: onDetach
Fragment4: onCreateView
Fragment4: onStart

ไปที่ Fragment4

Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy

FragmentPagerAdapter

ไปที่ Fragment1 (กิจกรรมการเปิดตัว)

Fragment1: onCreateView
Fragment1: onStart
Fragment2: onCreateView
Fragment2: onStart

ไปที่ Fragment2

Fragment3: onCreateView
Fragment3: onStart

ไปที่ Fragment3

Fragment1: onStop
Fragment1: onDestroyView
Fragment4: onCreateView
Fragment4: onStart

ไปที่ Fragment4

Fragment2: onStop
Fragment2: onDestroyView

สรุป : FragmentStatePagerAdapterโทรหาonDestroyเมื่อแฟรกเมนต์ถูกเอาชนะoffscreenPageLimitขณะที่FragmentPagerAdapterไม่ได้

หมายเหตุ : ฉันคิดว่าเราควรใช้FragmentStatePagerAdapterสำหรับViewPagerที่มีหน้าเยอะเพราะมันจะดีต่อประสิทธิภาพ

ตัวอย่างของoffscreenPageLimit:

ถ้าเราไป Fragment3 ก็จะ detroy Fragment1 (หรือ Fragment5 ถ้ามี) offscreenPageLimit = 1เพราะ ถ้าเราตั้งoffscreenPageLimit > 1มันจะไม่ทำลาย
หากในตัวอย่างนี้เราตั้งค่าoffscreenPageLimit=4ไม่แตกต่างกันระหว่างการใช้FragmentStatePagerAdapterหรือFragmentPagerAdapterเนื่องจาก Fragment ไม่เคยโทรonDestroyViewและonDestroyเมื่อเราเปลี่ยนแท็บ

ตัวอย่าง Github ที่นี่


ช่างเป็นข้อสรุปที่ยอดเยี่ยม!
ราหุล Rastogi

คำอธิบายที่ดี
gourav singhal

1
คำอธิบายที่ดี คุณบอกว่าการใช้ FragmentStatePagerAdapter เมื่อมีหน้าจำนวนมากจะดีสำหรับประสิทธิภาพ คุณหมายถึงดีสำหรับการประหยัดหน่วยความจำหรือไม่? เป้าหมายตามที่ฉันเข้าใจคือการรักษาความทรงจำในกรณีที่เป็นไปได้หลายส่วน - ดังนั้นประสิทธิภาพจึงเป็นประโยชน์โดยปริยาย เป้าหมายที่ชัดเจนคือการรักษาความทรงจำไว้
Hatzil

38

บางสิ่งที่ไม่ได้กล่าวไว้อย่างชัดเจนในเอกสารประกอบหรือในคำตอบในหน้านี้ (แม้ว่านัยโดย @Naruto) คือสิ่งนั้นFragmentPagerAdapterจะไม่อัปเดตชิ้นส่วนหากข้อมูลใน Fragment เปลี่ยนแปลงเพราะมันเก็บส่วนในหน่วยความจำ

ดังนั้นแม้ว่าคุณจะมีจำนวนแฟรกเมนต์ที่ จำกัด ในการแสดงถ้าคุณต้องการที่จะรีเฟรชแฟรกเมนต์ของคุณ (พูดเช่นคุณรันเคียวรีใหม่เพื่ออัพเดต listView ใน Fragment) คุณต้องใช้ FragmentStatePagerAdapter

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


สมมติว่าฉันมี 2 แฟรกเมนต์, 1 recyclerview ในแฟรกเมนต์ A เมื่อฉันคลิกที่ไอเท็มมันจะเปลี่ยนเนื้อหาของแฟรกเมนต์ B บอกว่าฉันทำ fragB.setText ("blablabla") ฉันควรใช้เพจเจอร์ของรัฐแล้ว?
Ced

ไม่แน่นอน แต่ฉันจะบอกว่าใช่ ลองทั้งสองอย่างมันง่ายและรวดเร็วมากในการเปลี่ยนรหัสจากที่หนึ่งไปยังอีกที่หนึ่ง
JDenais

@JDenais คุณแน่ใจว่าถูกต้องหรือไม่ ฉันกำลังใช้FragmentPagerAdapterในกิจกรรมที่ใช้ ViewPager เพื่อแสดงแฟรกเมนต์สองรายการโดยที่แต่ละแฟรกเมนต์มีรายการ รายการแรกของฉันเรียกว่า "รายงานทั้งหมด" และรายการที่สองคือ "รายงานที่ชื่นชอบ" ในรายการแรกถ้าฉันแตะไอคอนรูปดาวสำหรับรายงานนั้นจะอัปเดตฐานข้อมูลเพื่อสลับสถานะรายการโปรดของรายงานนั้น จากนั้นฉันก็กวาดนิ้วไปมาแล้วก็เห็นรายงานนี้ใน UI ของรายการที่สอง ดังนั้นอินสแตนซ์อาจถูกเก็บไว้ในหน่วยความจำ แต่ในบางกรณี (เช่นของฉัน) เนื้อหาจะอัปเดตได้ดีสำหรับ FragmentPagerAdapter
ban-geoengineering

14

FragmentPagerAdapterเก็บข้อมูลก่อนหน้าซึ่งดึงมาจากอะแดปเตอร์ในขณะที่FragmentStatePagerAdapterรับค่าใหม่จากอะแดปเตอร์ทุกครั้งที่มีการดำเนินการ


4

FragmentStatePagerAdapter = เพื่อรองรับชิ้นส่วนจำนวนมากใน ViewPager เนื่องจากอะแด็ปเตอร์นี้จะทำการแตกแฟรกเมนต์เมื่อผู้ใช้ไม่สามารถมองเห็นได้และมีการบันทึกไว้เท่านั้นอินสแตนซ์ของแฟรกเมนต์จะถูกเก็บไว้เพื่อการใช้งานต่อไป วิธีนี้มีการใช้หน่วยความจำในปริมาณต่ำและประสิทธิภาพที่ดีขึ้นจะถูกส่งในกรณีที่มีชิ้นส่วนแบบไดนามิก


1

FragmentPagerAdapter : แฟรกเมนต์ของแต่ละหน้าที่ผู้ใช้เยี่ยมชมจะถูกเก็บไว้ในหน่วยความจำแม้ว่ามุมมองจะถูกทำลาย ดังนั้นเมื่อหน้านั้นสามารถมองเห็นได้อีกครั้งมุมมองจะถูกสร้างขึ้นใหม่ แต่อินสแตนซ์ส่วนที่ไม่ได้สร้างขึ้นใหม่ ซึ่งอาจส่งผลให้มีการใช้หน่วยความจำจำนวนมาก FragmentPagerAdapter ควรใช้เมื่อเราต้องการเก็บส่วนทั้งหมดในหน่วยความจำ FragmentPagerAdapter เรียก detach (Fragment) ในการทำธุรกรรมแทนการลบ (Fragment)

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.