ล้างสแต็กกลับโดยใช้แฟรกเมนต์


244

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

ตอนนี้แอพของฉันเป็นเพียงกิจกรรมเดียวที่มีหลายแฟรกเมนต์ดังนั้นเมื่อฉันกดปุ่มโฮมฉันเพิ่งแทนที่หนึ่งในแฟรกเมนต์ที่อยู่ภายใน ฉันจะล้าง back stack ของฉันโดยไม่ต้องใช้startActivityกับACTIVITY_CLEAR_TOPค่าสถานะได้อย่างไร


หลีกเลี่ยงการใช้กองหลัง! มันไม่ได้ช่วยในเรื่องประสิทธิภาพโดยรวม! ใช้การแทนที่แบบธรรมดา () หรือดีกว่าการลบ / เพิ่มทุกครั้งที่คุณต้องการนำทาง! ตรวจสอบโพสต์ของฉันในstackoverflow.com/questions/5802141/…
stack_ved

คำตอบ:


430

ฉันโพสต์สิ่งที่คล้ายกันที่นี่

จากคำตอบของโจอาคิมจาก Dianne Hackborn:

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

ฉันลงเอยด้วยการใช้:

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

แต่สามารถใช้บางอย่างเช่น:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

ซึ่งจะปรากฏสถานะทั้งหมดขึ้นกับชื่อที่ระบุ จากนั้นคุณสามารถแทนที่ชิ้นส่วนด้วยสิ่งที่คุณต้องการ


8
มันเทียบเท่ากับการกดปุ่มย้อนกลับหนึ่งครั้งขึ้นไปดังนั้นมันจึงเปลี่ยนส่วนที่มองเห็นได้ในปัจจุบัน (อย่างน้อยตอนที่ฉันได้ลอง)
Peter Ajtai

7
ฉันมีปัญหาเดียวกันกับปีเตอร์ ฉันต้องการที่จะกำจัดของเสียทั้งหมดออกไปแทนที่จะปล่อยให้มันวนผ่านสิ่งเหล่านั้นซึ่งมีความหมายมากมาย ตัวอย่างเช่นคุณจะเข้าสู่เหตุการณ์รอบอายุที่คุณไม่จำเป็นต้องทำโดยการแตกทุกส่วนออกจากสแต็กตามลำดับ
Brian Griffey

233
หากต้องการไปด้านบนให้ใช้เพียง: FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
Warpzit

53
สำหรับสิ่งที่คุ้มค่าใช้ fragmentManager popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) ทำงานได้ดียิ่งขึ้นสำหรับฉันเพราะมันทำให้แอนิเมชั่นชิ้นส่วนไม่สามารถทำงานได้
roarster

17
สิ่งนี้ไม่ทำงานอย่างถูกต้อง - มันจะทริกเกอร์การเรียกไปยัง onStart ของทุกส่วนในระหว่าง
James

165

เพื่อให้คำตอบสำหรับความคิดเห็นของ @ Warpzit และทำให้ผู้อื่นหาง่ายขึ้น

ใช้:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
ฉันเชื่อว่าการแตกชิ้นส่วนทั้งหมดจากแบ็คสแต็คด้วยวิธีนี้แตกในไลบรารี v7-appCompat ล่าสุดเมื่อใช้ AppCompatActivity หลังจากอัปเดตแอปของฉันเป็นไลบรารี่ v7-appCompat ล่าสุด (21.0.0) และขยาย AppCompatActivity ใหม่การแตกแฟรกเมนต์ในลักษณะด้านบนคือการทิ้งแฟรกเมนต์บางส่วนในเร็กคอร์ดหลังของ FragmentManager ฉันแนะนำไม่ให้ใช้สิ่งนี้
dell116

อาจจะใช้ popBackStackImmediate
Kannan_SJD

38

ด้วยความเคารพจากทุกฝ่ายที่เกี่ยวข้อง; ฉันประหลาดใจมากที่เห็นว่าคุณมีกี่คนที่สามารถล้างข้อมูลส่วนหลังทั้งหมดด้วยวิธีง่ายๆ

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

ตามเอกสาร Android (เกี่ยวกับnameข้อโต้แย้ง - "โมฆะ" ในข้อเสนอการทำงานที่อ้างสิทธิ์)

หากเป็นโมฆะเฉพาะสถานะบนสุดเท่านั้นที่จะปรากฏ

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

(สำหรับการอ้างอิงบางสิ่งพร้อมกับสิ่งนี้)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

4
สำหรับฉันมันไม่ได้เป็นเพราะแต่ละป๊อปจะพาคุณไปยังonCreateViewของแต่ละส่วน ฉันจะรับ NPE ได้ที่ไหนในทรัพยากรบางอย่าง แต่ใช้fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) เพียงฆ่าแบ็คสแต็คทั้งหมด
sud007

1
ข้อมูลเชิงลึกเกี่ยวกับวิธีข้ามสาย onCreateView เมื่อเปิดใช้ลูป
Ayush Goyal

การล้างแฟรกเมนต์ส่วนใหญ่ด้านบน (null) จะล้างแฟรกเมนต์ทั้งหมดที่อยู่หลังในสแต็กหลัง
2b77bee6-5445-4c77-b1eb-4df3e5

18

เหมาะสำหรับฉันและวิธีที่ง่ายโดยไม่ต้องใช้วงวน:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

17

คำตอบที่ยอมรับไม่เพียงพอสำหรับฉัน ฉันต้องใช้:

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

2
นี่เป็นคำตอบที่แตกต่างออกไป แต่เพื่อให้แน่ใจว่ามีการบันทึกไว้: หากคุณปรากฏสแต็กทั้งหมดในลูปแบบนี้คุณจะเรียกวิธีการรอบการทำงานสำหรับทุกส่วนในระหว่างการเริ่มต้นและสิ้นสุดของสแต็ก . มีโอกาสที่ดีที่การใช้งานนี้จะมีผลที่ไม่ตั้งใจในกรณีการใช้งานส่วนใหญ่ นอกจากนี้ยังควรค่าแก่การชี้ให้เห็นว่าpopBackStackImmediate()การทำธุรกรรมโดยรวมซึ่งโดยทั่วไปไม่ได้รับคำแนะนำ
Damien Diehl

16

ล้าง backstack โดยไม่มีลูป

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

โดยที่nameคือพารามิเตอร์ addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

แม้ว่าคุณจะแทนที่. fragment stack จะยังมีชีวิตอยู่ แต่มองไม่เห็น
Asthme

8

ฉันแค่อยากจะเพิ่ม: -

โผล่ออกมาจากแบ็คสแต็คโดยใช้ดังต่อไปนี้

fragmentManager.popBackStack ()

เป็นเพียงการลบแฟรกเมนต์ออกจากธุรกรรมไม่มีทางที่จะลบแฟรกเมนต์ออกจากหน้าจอ ดังนั้นอาจไม่สามารถมองเห็นคุณได้ แต่อาจมีสองหรือสามชิ้นซ้อนกันและกดปุ่มย้อนกลับ UI อาจดูรกซ้อนกัน

แค่ยกตัวอย่างง่ายๆ: -

สมมติว่าคุณมี FragmentA ซึ่งโหลด Fragmnet B โดยใช้Fragmentmanager.replace ()จากนั้นเราเพิ่ม addToBackStack เพื่อบันทึกธุรกรรมนี้ ดังนั้นการไหลคือ: -

ขั้นตอนที่ 1 -> FragmentA-> FragmentB (เราย้ายไปที่ FragmentB แต่ Fragment A อยู่ในพื้นหลังไม่สามารถมองเห็นได้)

ตอนนี้คุณทำงานชิ้นส่วน B แล้วกดปุ่มบันทึกซึ่งหลังจากบันทึกแล้วควรกลับไปที่ชิ้นส่วน A

ขั้นตอนที่ 2-> เมื่อบันทึก FragmentB เรากลับไปที่ FragmentA

ขั้นตอนที่ 3 -> ความผิดพลาดที่พบบ่อยคือ ... ใน Fragment B เราจะทำการแยกส่วน Manager.replace () fragmentB ด้วย FragmentA

แต่สิ่งที่เกิดขึ้นจริงเรากำลังโหลด Fragment A อีกครั้งแทนที่ FragmentB ตอนนี้มี FragmentA สองอัน (อันจาก STEP-1 และอีกอันจาก STEP-3)

อินสแตนซ์ของ FragmentsA สองรายการซ้อนกันซึ่งอาจมองไม่เห็น แต่มีอยู่

ดังนั้นแม้ว่าเราจะล้าง backstack ด้วยวิธีการข้างต้น แต่การทำธุรกรรมจะถูกล้าง แต่ไม่ใช่เศษที่เกิดขึ้นจริง ดังนั้นในกรณีพิเศษโดยเฉพาะเมื่อกดปุ่มบันทึกคุณเพียงแค่ต้องกลับไปที่ FragmentA โดยทำfm.popBackStack ()หรือfm.popBackImmediate ()()

ดังนั้นแก้ไข Step3-> fm.popBackStack () กลับไปที่ fragmentA ซึ่งมีอยู่ในหน่วยความจำแล้ว


3

การอ่านเอกสารและศึกษาว่า id ของแฟรกเมนต์เป็นอย่างไรดูเหมือนว่าเป็นดัชนีสแต็กดังนั้นการทำงาน:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

ศูนย์ (0 ) คือด้านล่างของสแต็คดังนั้นการ popping up รวมถึงการเคลียร์สแต็ก

ถ้ำ: ถึงแม้ว่าโปรแกรมข้างต้นจะทำงานในโปรแกรมของฉัน แต่ฉันลังเลเล็กน้อยเพราะเอกสาร FragmentManager ไม่เคยระบุว่า id เป็นดัชนีสแต็ก มันสมเหตุสมผลแล้วและบันทึกการดีบั๊กทั้งหมดของฉันเปิดออกว่ามันเป็นไปได้ แต่บางทีในบางกรณีพิเศษมันจะไม่ได้หรือไม่ ใครสามารถยืนยันวิธีนี้หรืออีกวิธีหนึ่ง? ถ้าเป็นเช่นนั้นสิ่งที่กล่าวมาข้างต้นเป็นทางออกที่ดีที่สุด ถ้าไม่เป็นทางเลือกนี้:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

1
วิธีการเกี่ยวกับการใช้fragmentManager..getBackStackEntryAt(0).getId()แทน 0? สิ่งนี้จะใช้ได้แม้ว่ารหัสแบ็คสแลคจะมีจุดแตกต่างจากดัชนีสแต็ก
ChristophK

3

เพียงใช้วิธีนี้แล้วส่งแท็ก Context & Fragment ไปจนสุดซึ่งเราจำเป็นต้องลบส่วนที่อยู่ด้านหลังออก

การใช้

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

2

สวัสดี ~ ฉันพบวิธีแก้ปัญหาที่ดีกว่ามากจาก: https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

2
โปรดขยายคำตอบของคุณด้วยสาเหตุที่โซลูชันนี้ดีกว่า
Simon.SA

มันใช้กลไกที่ sdk ให้ตัวเองและจะไม่ทำให้เกิดปัญหา npe
Chenxi

1

ฉันได้ทำงานนี้ด้วยวิธีนี้:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

1

มันใช้งานได้สำหรับฉันลองอันนี้:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

การโทรไปที่วิธีนี้คงจะเรียบร้อยมาก

  1. ไม่จำเป็นต้องวนซ้ำ
  2. หากคุณใช้ภาพเคลื่อนไหวเป็นชิ้นส่วนมันจะไม่แสดงภาพเคลื่อนไหวมากเกินไป แต่การใช้ลูปจะ

0
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

ขอขอบคุณสำหรับข้อมูลโค้ดนี้ซึ่งอาจให้ความช่วยเหลือแบบ จำกัด และทันที คำอธิบายที่เหมาะสมมากจะเพิ่มมูลค่าในระยะยาวด้วยการแสดงเหตุผลนี้เป็นทางออกที่ดีในการแก้ไขปัญหาและจะทำให้มันมีประโยชน์มากขึ้นให้กับผู้อ่านในอนาคตกับอื่น ๆ คำถามที่คล้ายกัน โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงข้อสมมติฐานที่คุณทำ
Abdelilah El Aissaoui
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.