การทำความเข้าใจ setRetainInstance ของชิ้นส่วน (บูลีน)


341

เริ่มต้นด้วยเอกสาร:

โมฆะสาธารณะ setRetainInstance (บูลีนเก็บ)

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

  • onDestroy () จะไม่ถูกเรียก (แต่ onDetach () จะยังคงอยู่เนื่องจากแฟรกเมนต์กำลังถูกแยกออกจากกิจกรรมปัจจุบัน)
  • onCreate (Bundle) จะไม่ถูกเรียกใช้เนื่องจากแฟรกเมนต์ไม่ได้ถูกสร้างขึ้นใหม่
  • onAttach (กิจกรรม) และ onActivityCreated (Bundle) จะยังคงถูกเรียกใช้

ฉันมีคำถาม:

  • แฟรกเมนต์ยังรักษามุมมองหรือไม่หรือสิ่งนี้จะถูกสร้างใหม่ตามการเปลี่ยนแปลงการกำหนดค่าหรือไม่? "เก็บรักษา" หมายความว่าอะไร?

  • ส่วนจะถูกทำลายเมื่อผู้ใช้ออกจากกิจกรรมหรือไม่

  • ทำไมมันไม่ทำงานกับเศษเล็กเศษน้อยในกองหลัง?

  • กรณีการใช้งานแบบไหนที่เหมาะสมกับการใช้วิธีนี้?


4
คำถามที่คล้ายกันพร้อมข้อมูลที่ดี: ทำไมจึงใช้ Fragment # setRetainInstance (boolean)
Richard Le Mesurier

คำตอบ:


348

ก่อนอื่นให้ลองดูโพสต์ของฉันในส่วนที่ถูกเก็บ มันอาจช่วยได้

ตอนนี้เพื่อตอบคำถามของคุณ:

ส่วนย่อยยังคงสถานะมุมมองหรือไม่หรือสิ่งนี้จะถูกสร้างขึ้นใหม่เมื่อมีการเปลี่ยนแปลงการกำหนดค่า - "คงไว้" คืออะไร?

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

ส่วนจะถูกทำลายเมื่อผู้ใช้ออกจากกิจกรรมหรือไม่

เช่นเดียวกับActivitys ระบบFragmentอาจถูกทำลายเมื่อทรัพยากรหน่วยความจำเหลือน้อย ไม่ว่าคุณจะมีชิ้นส่วนของคุณรักษารัฐอินสแตนซ์ของพวกเขาข้ามเปลี่ยนแปลงการกำหนดค่าจะไม่มีผลกระทบหรือไม่ว่าระบบจะทำลายFragments Activityเมื่อคุณออกจาก หากคุณออกจากActivity(เช่นโดยการกดปุ่มโฮม) Fragments อาจจะถูกทำลายหรือไม่ หากคุณออกจากการActivityกดปุ่มย้อนกลับ (เช่นการโทรfinish()และทำลายอย่างมีประสิทธิภาพActivity) Activitys ที่แนบมาทั้งหมดFragmentจะถูกทำลายเช่นกัน

ทำไมมันไม่ทำงานกับเศษเล็กเศษน้อยในกองหลัง?

อาจมีสาเหตุหลายประการที่ไม่รองรับ แต่เหตุผลที่ชัดเจนที่สุดสำหรับฉันคือการActivityอ้างอิงFragmentManagerและการFragmentManagerจัดการ backstack นั่นคือไม่ว่าคุณจะเลือกที่จะเก็บไว้Fragmentหรือไม่ก็ตามActivity(และดังนั้นFragmentManagerแบ็คสต็อกของ) จะถูกทำลายในการเปลี่ยนแปลงการกำหนดค่า อีกเหตุผลหนึ่งที่ทำให้มันใช้งานไม่ได้เพราะสิ่งต่าง ๆ อาจมีความยุ่งยากหากทั้งชิ้นส่วนที่เก็บไว้และชิ้นส่วนที่ไม่ได้รับการเก็บรักษาได้รับอนุญาตให้อยู่บน backstack เดียวกัน

กรณีการใช้งานแบบไหนที่เหมาะสมกับการใช้วิธีนี้?

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

โดยทั่วไปแล้วฉันจะถือว่ามันเหมือนกับการใช้onConfigurationChangedกับActivity... อย่าใช้มันเป็น bandaid เพียงเพราะคุณขี้เกียจเกินกว่าที่จะนำไปใช้ / จัดการกับการเปลี่ยนทิศทางได้อย่างถูกต้อง ใช้งานได้เฉพาะเมื่อคุณต้องการ


37
มุมมองวัตถุจะไม่ถูกเก็บไว้ แต่จะถูกทำลายเมื่อมีการเปลี่ยนแปลงการกำหนดค่า
Markus Junginger

103
เท่าที่ผมสามารถบอกได้ว่าถ้าคุณมีsetRetainInstance(true)ที่Fragmentวัตถุ Java และเนื้อหาทั้งหมดจะไม่ถูกทำลายในการหมุน แต่มุมมองเป็นบิ๊กแบง นั่นคือonCreatedView()เรียกอีกครั้ง มันเป็นวิธีการทำงานกับActivitiesAndroid 1.0 ฉันไม่คิดว่ามันเป็น "ขี้เกียจ" ที่จะใช้มันหรือการใช้มันไม่ "เหมาะสม" ในความเป็นจริงฉันไม่สามารถเห็นได้ว่าทำไมมันไม่ได้เป็นค่าเริ่มต้นหรือทำไมคุณถึงต้องการออก
Timmmm

24
ฉันพบคำอธิบายของคุณสำหรับ "ทำไมมันไม่ทำงานกับเศษเล็กเศษน้อยในกองหลัง?" ยากที่จะเข้าใจ. แต่บางทีฉันอาจจะโง่ :(
HGPB

13
@dierre กิจกรรมสามารถถูกทำลายได้หลายวิธี ตัวอย่างเช่นหากคุณคลิก "ย้อนกลับ" กิจกรรมจะถูกทำลาย หากคุณคลิก "บ้าน" กิจกรรมจะหยุดและบางครั้งในอนาคตอาจถูกทำลายเมื่อหน่วยความจำเหลือน้อย สะสมFragments จะถูกเก็บไว้เพียงข้ามเปลี่ยนแปลงการกำหนดค่าที่กิจกรรมพื้นฐานที่จะถูกทำลายและสร้างทันที ในกรณีอื่น ๆ ทั้งหมดที่กิจกรรมถูกทำลายชิ้นส่วนที่เก็บไว้จะถูกทำลายเช่นกัน
Alex Lockwood

3
@AlexLockwood โปรดยืนยันสิ่งต่อไปนี้: แม้ว่าจะsetRetainInstance(true)ถูกใช้งานอยู่แต่ก็ยังต้องใช้ความพยายามของตนเอง ( savedInstanceStateหรืออย่างอื่น) ในการจัดการกับสถานการณ์ทั้งหมด: เช่น "ปุ่มโฮมหมุนกลับไปที่แอพ" สร้างส่วนของฉันใหม่ โทรสูญเสียตัวแปรสถานะทั้งหมด ฉันมีAsyncTaskตัวแปรในฐานะสมาชิกนั่นคือสาเหตุที่ฉันต้องการเก็บไว้ตอนนี้ถ้าฉันต้องการให้มันทำงานฉันถูกบังคับให้หยุดภารกิจบันทึกสถานะและดำเนินการต่อเมื่อผู้ใช้กลับมา ดังนั้นโดยรวมนี่เป็นเพียงวิธีที่รวดเร็วในการช่วยหมุน แต่โดยทั่วไปก็ไม่มีประโยชน์
TWiStErRob

28

setRetaininstanceเป็นประโยชน์เฉพาะเมื่อคุณถูกทำลายและสร้างขึ้นจากการเปลี่ยนแปลงการกำหนดค่าเพราะกรณีจะถูกบันทึกไว้ในระหว่างการโทรไปยังactivity onRetainNonConfigurationInstanceนั่นคือถ้าคุณหมุนอุปกรณ์ชิ้นส่วนที่เก็บไว้จะยังคงอยู่ที่นั่น (จะไม่ถูกทำลายและสร้างใหม่) แต่เมื่อรันไทม์ฆ่ากิจกรรมเพื่อเรียกคืนทรัพยากรไม่มีสิ่งใดเหลืออยู่ เมื่อคุณกดปุ่มย้อนกลับและออกจากกิจกรรมทุกอย่างจะถูกทำลาย

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


คุณสร้างแฟรกเมนต์ "Data-Only" (ไม่มีวิดเจ็ตใด ๆ ) เพียงแค่เป็นตัวยึดสำหรับบิตแมปของคุณหรือแฟรกเมนต์เหล่านั้นมีวิดเจ็ตด้วยหรือไม่ ฉันได้อ่านบางสิ่งเกี่ยวกับอันตรายของการรั่วไหลของหน่วยความจำเมื่อ
แฟรกเมนต์

กรอบงานจะล้างmActivityข้อมูลอ้างอิงให้คุณ แต่ฉันไม่รู้ว่ารันไทม์จะล้างวิดเจ็ตในอินสแตนซ์แฟรกเมนต์ในกรณีนี้หรือไม่ กรุณาลองหรือดำดิ่งลงในซอร์สโค้ด
suitianshi

ตัวอย่างที่ดีของเมื่อเราสามารถใช้ setRetaininstance
Mu Sa

12

SetRetainInstance (จริง) อนุญาตให้เรียงลำดับของการเอาตัวรอด สมาชิกจะถูกเก็บไว้ระหว่างการเปลี่ยนแปลงการกำหนดค่าเช่นการหมุน แต่มันก็ยังอาจถูกฆ่าเมื่อกิจกรรมถูกฆ่าในพื้นหลัง หากกิจกรรมที่มีอยู่ในพื้นหลังถูกฆ่าโดยระบบมันควรจะบันทึก instanceState โดยระบบที่คุณจัดการบน SaveServerState อย่างถูกต้อง อีกนัยหนึ่ง onSaveInstanceState จะถูกเรียกใช้เสมอ แม้ว่า onCreateView จะไม่ถูกเรียกใช้หาก SetRetainInstance เป็นจริงและชิ้นส่วน / กิจกรรมยังไม่ถูกฆ่า แต่ก็ยังคงถูกเรียกใช้ถ้ามันถูกฆ่าและพยายามนำกลับมา

นี่คือการวิเคราะห์กิจกรรม Android / แฟรกเมนต์บางส่วนหวังว่าจะช่วยได้ http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html


8
แน่นอนฉันเห็น onCreateView ถูกเรียกอีกครั้งในชิ้นส่วนที่สะสมเมื่อหมุนหน้าจอ
aij

ลิงก์นี้เป็นบล็อกของคุณหรือไม่ คุณควรทำให้ชัดเจนหากเป็นกรณีนี้
เฟล็กโซ

4

setRetainInstance () - เลิกใช้แล้ว

As Fragments เวอร์ชั่น 1.3.0-alpha01

เมธอด setRetainInstance () บนแฟรกเมนต์เลิกใช้แล้ว ด้วยการเปิดตัว ViewModels นักพัฒนามี API เฉพาะสำหรับการเก็บรักษาสถานะที่สามารถเชื่อมโยงกับกิจกรรมชิ้นส่วนและกราฟการนำทาง สิ่งนี้ช่วยให้นักพัฒนาสามารถใช้งานปกติไม่แยกส่วนและรักษาสถานะเฉพาะที่พวกเขาต้องการเก็บไว้แยกต่างหากหลีกเลี่ยงแหล่งที่มาของการรั่วไหลทั่วไปในขณะที่ยังคงรักษาคุณสมบัติที่มีประโยชน์ของการสร้างเดียวและทำลายสถานะคงค้าง และการเรียกกลับ onCleared () ที่ได้รับ)


2

setRetainInstance (บูลีน)มีประโยชน์เมื่อคุณต้องการมีองค์ประกอบบางอย่างที่ไม่ได้ผูกติดอยู่กับวงจรชีวิตของกิจกรรม เทคนิคนี้ใช้สำหรับตัวอย่างโดยrxloaderเพื่อ "จัดการ lifecyle กิจกรรม Android สำหรับ rxjava's Observable" (ซึ่งฉันได้พบที่นี่ )

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