นี่เป็นวิธีที่ถูกต้องในการล้างสแต็ก Fragment back เมื่อออกจากสแต็กซ้อนกันหรือไม่?


130

ฉันกำลังใช้ไลบรารีความเข้ากันได้ของ Android เพื่อนำแฟรกเมนต์มาใช้และขยายตัวอย่างเลย์เอาต์เพื่อให้แฟรกเมนต์มีปุ่มที่จะดับแฟรกเมนต์อื่น

ในบานหน้าต่างตัวเลือกทางด้านซ้ายผมมี 5 รายการตัวเลือก A B C D E-

แต่ละโหลดชิ้นส่วน (ผ่านFragmentTransaction:replace) ในบานหน้าต่างรายละเอียด -a b c d e

ตอนนี้ฉันได้ขยายแฟรกเมนต์eเพื่อให้มีปุ่มซึ่งโหลดแฟรกเมนต์อื่นขึ้นe1ในบานหน้าต่างรายละเอียด ฉันทำสิ่งนี้ในeวิธี onClick ของส่วนดังนี้

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

ถ้าฉันทำการเลือกต่อไปนี้:

E - e - e1 - D - E

ส่วนนั้นeอยู่ในบานหน้าต่างรายละเอียด นี่คือสิ่งที่ดีและสิ่งที่ฉันต้องการ อย่างไรก็ตามถ้าฉันกดbackปุ่ม ณ จุดนี้มันไม่ทำอะไรเลย ฉันต้องคลิกสองครั้งเพราะe1ยังอยู่ในสแต็ก นอกจากนี้หลังจากคลิกไปรอบ ๆ ฉันได้รับข้อยกเว้นตัวชี้โมฆะใน onCreateView:

หากต้องการ 'แก้ปัญหา' ฉันได้เพิ่มสิ่งต่อไปนี้เมื่อใดก็ตามที่A B C D Eเลือก:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
    fm.popBackStack();
}

แค่สงสัยว่านี่เป็นทางออกที่ถูกต้องหรือไม่หรือว่าฉันควรจะทำอะไรที่แตกต่างออกไป?

คำตอบ:


252

มีหลายวิธีที่จะทำสิ่งนี้ขึ้นอยู่กับพฤติกรรมที่ต้องการ แต่ลิงค์นี้ควรให้ทางออกที่ดีที่สุดแก่คุณและไม่น่าแปลกใจจาก Dianne Hackborn

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

เป็นหลักคุณมีตัวเลือกดังต่อไปนี้

  • FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)ใช้ชื่อของรัฐกลับสแต็คครั้งแรกของคุณและการใช้งาน
  • การใช้FragmentManager.getBackStackEntryCount()/ การดึงประชาชนของรายการแรกในกองหลังและgetBackStackEntryAt().getId() FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE)
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) ควรจะปรากฏทั้งกองหลัง ... ฉันคิดว่าเอกสารที่ผิด (จริงๆแล้วฉันเดาว่ามันไม่ได้ครอบคลุมกรณีที่คุณส่งผ่านPOP_BACK_STACK_INCLUSIVE)

สิ่งนี้หมายความว่า? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). getId ()
dannyroa

4
2nd ทำงานสำหรับฉัน การล้างสแต็กทั้งหมดหมายถึงอะไร: getSupportFragmentManager (). popBackStack (getSupportFragmentManager (). getBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE
NickL

@JorgeGarcia เป็นไปได้หลังจาก popbackstack เราเพิ่งเสร็จสิ้นส่วนของเราโดยไม่ต้องรีสตาร์ทเก่า
duggu

โปรดทราบว่ายังมีรุ่น popBackStackImmediate () เนื่องจาก popBackStack () เป็น async ซึ่งหมายความว่าการล้างค่าจะไม่เกิดขึ้นในเวลาที่คุณเรียกใช้เมธอด
Genc

6
อ้างว่ากลุ่มถูกแบนเป็นสแปมและฉันไม่สามารถเข้าถึงลิงค์ :( ไม่มีใครมีทรัพยากรที่อื่นหรือไม่
EpicPandaForce

61

อีกวิธีที่สะอาดหากคุณไม่ต้องการที่จะปรากฏรายการสแต็กทั้งหมด ...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

วิธีนี้จะทำความสะอาดสแต็กก่อนแล้วจึงโหลดชิ้นส่วนใหม่ดังนั้น ณ จุดใดก็ตามคุณจะมีเพียงส่วนเดียวในสแต็ก


1
นี้จะไม่ดีมาก: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);ก่อนที่จะมาแทนที่ () เนื่องจากมีการโหลดโทร Fragment onCreateView(), onActivityCreated()ฯลฯ และการกู้คืน Destroing ชิ้นทันทีไม่ดี Fragment สามารถลงทะเบียนผู้รับได้ สิ่งนี้มีผลต่อประสิทธิภาพ
VasileM

@VasileM คุณช่วยอธิบายรายละเอียดได้ไหม? ในกรณีใดบ้างที่ไม่ดี มันเป็นเพราะพฤติกรรมแบบ asynhronous ของFragmentTransaction? มีเพียงประสิทธิภาพที่ดีของสแตกแฟรกเมนต์ที่ไม่ถูกต้องหรือ
CoolMind

27

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

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */

18
ทำไมต้องใช้การวนซ้ำที่นี่ สำหรับฉัน FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) ลบรายการสแต็กกลับทั้งหมด ...
Marek

3
@Marek เพราะบางครั้งไม่ควรลบออกทั้งหมดชิ้นส่วนเหมาะสำหรับสิ่งนี้
CoolMind

1
@ CoolMind ที่ยังไม่สมเหตุสมผลกับฉัน popBackStack(backStackId, INCLUSIVE)จะป๊อปอัพแฟรกเมนต์ทั้งหมด (สถานะ) กลับไปที่ backStackId ดังนั้นเมื่อคุณปรากฏป๊อปอัปต่ำสุดiที่คุณจะป๊อปชิ้นส่วนที่สูงกว่าทั้งหมดจะโผล่ขึ้นมาพร้อมกัน ดังนั้นจุดของลูปคืออะไร?
LarsH

@ LarsH คุณพูดถูก ดูstackoverflow.com/a/59158254/2914140 เพื่อให้สามารถแตกแฟรกเมนต์อื่น ๆ ไปยังแท็กที่ต้องการได้อันดับแรกเราควรเพิ่มแฟรกเมนต์ด้วย addToBackStack ( แท็ก )
CoolMind

7

ผมได้ค้นคว้ามากสำหรับการทำความสะอาด Backstack และในที่สุดก็เห็นการทำธุรกรรม BackStack และผู้บริหารของ นี่คือทางออกที่ได้ผลดีที่สุดสำหรับฉัน

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

วิธีการข้างต้นวนซ้ำธุรกรรมทั้งหมดในแบ็คสแต็คและลบออกทีละรายการทันที

หมายเหตุ:รหัสข้างบนบางครั้งไม่ทำงานและฉันเผชิญANRเพราะรหัสนี้ดังนั้นโปรดอย่าลองนี้

วิธีการอัปเดตด้านล่างจะลบ "ชื่อ" ทั้งหมดออกจาก backstack

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • ชื่อถ้าไม่ใช่ - โมฆะนี่คือชื่อของรัฐหลังก่อนที่จะมองหา; หากพบว่าทุกรัฐที่อยู่ในสถานะนั้นจะถูกตอก
  • สามารถใช้การตั้งค่าสถานะ POP_BACK_STACK_INCLUSIVE เพื่อควบคุมว่าสถานะที่กำหนดเองนั้นถูกเปิดขึ้นมา หากเป็นโมฆะเฉพาะสถานะบนสุดเท่านั้นที่จะปรากฏ

ฉันไม่เห็นสาเหตุที่คุณจะลบทีละครั้ง มีเหตุผลที่คุณเลือกใช้โซลูชันนี้แทนที่จะเป็นโซลูชันอื่นหรือไม่? มีเหตุผลที่จะลบออกทีละรายการแทนที่จะทำทีละรายการหรือไม่?
miva2

thair ไม่มีวิธีลบ backstack ในครั้งเดียวโปรดดูdeveloper.android.com/reference/android/app/ …
Lokesh

3

ฉันใช้รหัสที่คล้ายกันกับที่ใช้ขณะที่ห่วง แต่ฉันเรียกนับรายการในทุกวง ... ดังนั้นฉันคิดว่ามันค่อนข้างช้า

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }

0

ดังที่เขียนไว้ในวิธีการแยกชิ้นส่วนออกจากแบ็คสแต็กและโดยLarsHที่นี่เราสามารถป๊อปแยกชิ้นส่วนจากบนลงล่างไปยังแท็ก specifical ( พร้อมกับชิ้นส่วนที่ติดแท็ก ) โดยใช้วิธีนี้:

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

แทน "frag" ด้วยแท็ก fragment ของคุณ จำไว้ว่าก่อนอื่นเราควรเพิ่มส่วนเพื่อ backstack ด้วย:

fragmentTransaction.addToBackStack("frag")

หากเราเพิ่มแฟรกเมนต์ด้วยaddToBackStack(null)เราจะไม่แสดงแฟรกเมนต์ด้วยวิธีนั้น


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.