Xóa ngăn xếp trở lại bằng cách sử dụng các mảnh


244

Tôi đã chuyển ứng dụng Android của mình sang tổ ong và tôi đã thực hiện một phép tái cấu trúc lớn để sử dụng các đoạn. Trong phiên bản trước của tôi, khi tôi nhấn nút Home, tôi đã từng thực hiện ACTIVITY_CLEAR_TOPđể đặt lại ngăn xếp phía sau.

Bây giờ ứng dụng của tôi chỉ là một Hoạt động đơn lẻ với nhiều phân đoạn, vì vậy khi tôi nhấn nút Home, tôi chỉ cần thay thế một trong các phân đoạn bên trong nó. Làm thế nào tôi có thể xóa ngăn xếp trở lại của tôi mà không phải sử dụng startActivityvới ACTIVITY_CLEAR_TOPcờ?


Tránh sử dụng ngăn xếp trở lại! nó không thực sự giúp với hiệu quả tổng thể! sử dụng thay thế đơn giản () hoặc thậm chí tốt hơn loại bỏ / thêm mỗi lần bạn muốn điều hướng! Kiểm tra bài đăng của tôi trên stackoverflow.com/questions/5802141/ Cách
stack_ved

Câu trả lời:


430

Tôi đã đăng một cái gì đó tương tự ở đây

Từ câu trả lời của Joachim, từ Dianne Hackborn:

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

Tôi đã kết thúc chỉ bằng cách sử dụng:

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

Nhưng cũng có thể sử dụng một cái gì đó như:

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

Mà sẽ bật tất cả các trạng thái lên đến cái được đặt tên. Sau đó, bạn có thể chỉ cần thay thế các mảnh bằng những gì bạn muốn


8
Chà, nó tương đương với việc nhấn nút quay lại một hoặc nhiều lần, vì vậy nó thay đổi đoạn hiện đang nhìn thấy. (Ít nhất là khi tôi đã thử nó)
Peter Ajtai

7
Tôi đang có vấn đề tương tự như peter. Tôi muốn xóa tất cả các mảnh vỡ hơn là chuyển nó qua chúng có rất nhiều hàm ý. Ví dụ: bạn sẽ nhấn các sự kiện trong vòng đời mà bạn không cần bằng cách bật từng đoạn ra khỏi ngăn xếp một cách tuần tự.
Brian Griffey

233
Để lên đầu, chỉ cần sử dụng: FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit

53
Đối với những gì nó có giá trị, sử dụng FragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); làm việc thậm chí còn tốt hơn đối với tôi vì nó ngăn chặn các hoạt hình mảnh vỡ thực thi
roarster

17
Điều này KHÔNG hoạt động đúng - nó sẽ kích hoạt một cuộc gọi đến Bắt đầu mọi đoạn ở giữa
James

165

Để đưa ra câu trả lời cho nhận xét của @ Warpzit và giúp người khác dễ dàng tìm thấy hơn.

Sử dụng:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
Tôi tin rằng việc bật tất cả các đoạn từ backstack theo cách này đã bị phá vỡ trong thư viện v7-appCompat mới nhất khi sử dụng AppCompatActivity. Sau khi cập nhật ứng dụng của tôi lên thư viện v7-appCompat mới nhất (21.0.0) và mở rộng AppCompatActivity mới, xuất hiện các đoạn theo cách trên sẽ để lại một số đoạn trong bản ghi backstack của FragmentManager. Tôi khuyên bạn không nên sử dụng cái này.
dell116

Có thể được sử dụng popBackStackImmediate.
Kannan_SJD

38

Với tất cả sự tôn trọng đối với tất cả các bên liên quan; Tôi rất ngạc nhiên khi thấy có bao nhiêu trong số các bạn có thể xóa toàn bộ ngăn xếp lại mảnh một cách đơn giản

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Theo tài liệu của Android (liên quan đến nameđối số - "null" trong các đề xuất làm việc được yêu cầu).

Nếu null, chỉ trạng thái trên cùng được bật

Bây giờ, tôi nhận ra rằng tôi đang thiếu kiến ​​thức về các triển khai cụ thể của bạn (như có bao nhiêu mục bạn có trong ngăn xếp ngược tại thời điểm đã cho), nhưng tôi sẽ đặt cược tất cả tiền của mình vào câu trả lời được chấp nhận khi mong đợi được xác định rõ hành vi trên một loạt các thiết bị và nhà cung cấp:

(để tham khảo, một cái gì đó cùng với điều này)

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

4
đối với tôi, đó không phải là vì mỗi cửa sổ pop đưa bạn vào nội bộ onCreateView của từng phân đoạn. Nơi tôi sẽ nhận được một NPE trên một số tài nguyên. Nhưng bằng cách sử dụng fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); Đơn giản là giết tất cả các backstack.
sud007

1
Bất kỳ hiểu biết nào về cách bỏ qua các cuộc gọi onCreateView khi bật bằng vòng lặp?
Ayush Goyalty

Xóa phần lớn nhất (null) sẽ xóa tất cả các phần xuất hiện sau phần trong ngăn xếp phía sau.
2b77bee6-5445-4c77-b1eb-4df3e5

18

Làm việc cho tôi và cách dễ dàng mà không cần sử dụng vòng lặp:

 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

Câu trả lời được chấp nhận là không đủ cho tôi. Tôi đã phải sử dụng:

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

2
Điều này đã được chỉ ra trong một câu trả lời khác, nhưng chỉ để đảm bảo rằng nó được ghi chú: Nếu bạn bật toàn bộ ngăn xếp trong một vòng lặp như thế này, bạn sẽ kích hoạt các phương thức vòng đời cho mỗi Mảnh vỡ ở giữa đầu và cuối ngăn xếp . Có một cơ hội tốt rằng việc thực hiện này sẽ có những hậu quả không lường trước được, trong hầu hết các trường hợp sử dụng. Cũng đáng để chỉ ra rằng popBackStackImmediate()thực hiện giao dịch một cách đồng bộ, nói chung, không được khuyến khích.
Damien Diehl

16

Xóa backstack không có vòng lặp

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

Nơi tên là addToBackStack () tham số

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

ngay cả khi bạn thay thế .fragment stack vẫn còn sống nhưng không hiển thị
Asthme

8

Tôi chỉ muốn thêm: -

Xuất hiện từ backstack bằng cách sử dụng sau

FragmentManager.popBackStack ()

chỉ là về việc loại bỏ các mảnh khỏi giao dịch, không có cách nào để loại bỏ các mảnh khỏi màn hình. Rất lý tưởng, nó có thể không hiển thị với bạn nhưng có thể có hai hoặc ba mảnh được xếp chồng lên nhau và trên phím quay lại, giao diện người dùng có thể trông lộn xộn, xếp chồng lên nhau.

Chỉ lấy một ví dụ đơn giản: -

Giả sử bạn có một đoạnA tải Fragmnet B bằng cách sử dụng Fragmentmanager.replace () và sau đó chúng tôi thực hiện addToBackStack, để lưu giao dịch này. Vì vậy, dòng chảy là: -

BƯỚC 1 -> FragmentA-> FragmentB (chúng tôi đã chuyển sang FragmentB, nhưng Fragment A ở chế độ nền, không hiển thị).

Bây giờ Bạn thực hiện một số công việc trong phân đoạnB và nhấn nút Lưu mà sau khi lưu sẽ quay lại phân đoạnA.

BƯỚC 2-> Khi lưu FragmentB, chúng tôi quay lại FragmentA.

BƯỚC 3 -> Vì vậy, lỗi phổ biến sẽ là ... trong Đoạn B, chúng tôi sẽ thực hiện phân đoạn Manager.replace () FragmentB với FragmentA.

Nhưng những gì thực sự đang xảy ra, chúng tôi đang tải lại Fragment A, thay thế FragmentB. Vì vậy, bây giờ có hai FragmentA (một từ BƯỚC-1 và một từ BƯỚC-3).

Hai trường hợp của FragmentsA được xếp chồng lên nhau, có thể không nhìn thấy được, nhưng nó ở đó.

Vì vậy, ngay cả khi chúng tôi xóa backstack bằng các phương thức trên, giao dịch sẽ bị xóa nhưng không phải là các mảnh thực tế. Vì vậy, lý tưởng trong trường hợp cụ thể như vậy, khi nhấn nút lưu, bạn chỉ cần quay lại FragmentA bằng cách thực hiện fm.popBackStack () hoặc fm.popBackImmediate () .

Vì vậy, sửa Step3-> fm.popBackStack () trở lại FragmentA, đã có trong bộ nhớ.


3

Đọc tài liệu và nghiên cứu id phân đoạn là gì, nó dường như chỉ là chỉ số ngăn xếp, vì vậy điều này hoạt động:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zero ( 0) là phần dưới cùng của ngăn xếp, do đó, việc bật lên bao gồm nó sẽ xóa sạch ngăn xếp.

CAVEAT: Mặc dù các cách trên hoạt động trong chương trình của tôi, tôi do dự một chút vì tài liệu FragmentManager không bao giờ thực sự nói rằng id là chỉ mục ngăn xếp. Nó có ý nghĩa rằng nó sẽ được, và tất cả các bản ghi gỡ lỗi của tôi chỉ ra rằng nó có, nhưng có lẽ trong một số trường hợp đặc biệt thì không? Có ai có thể xác nhận cách này hay cách khác không? Nếu có, thì ở trên là giải pháp tốt nhất. Nếu không, đây là lựa chọn thay thế:

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

1
Làm thế nào về việc sử dụng fragmentManager..getBackStackEntryAt(0).getId()thay vì 0? Điều này sẽ hoạt động ngay cả khi id mục nhập backstack tại một số điểm khác với chỉ số ngăn xếp.
ChristophK

3

Chỉ cần sử dụng phương pháp này và chuyển thẻ Bối cảnh & Mảnh vỡ mà chúng ta cần để loại bỏ các mảnh vỡ phía sau.

Sử dụng

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

Xin chào ~ Tôi đã tìm thấy một giải pháp tốt hơn nhiều, từ: 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
Hãy mở rộng câu trả lời của bạn với lý do tại sao giải pháp này là tốt hơn.
Simon.SA

Nó sử dụng cơ chế mà sdk tự cung cấp và sẽ không gây ra một số vấn đề về npe.
Chenxi

1

Tôi đã làm việc này theo cách này:

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

1

Nó đang làm việc cho tôi, hãy thử cái này:

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);
    }

Gọi cho phương pháp này sẽ rất gọn gàng.

  1. Không cần vòng lặp.
  2. Nếu bạn đang sử dụng hoạt hình theo từng mảnh, nó sẽ không hiển thị quá nhiều hình động. Nhưng sử dụng vòng lặp sẽ.

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;
}

Cảm ơn bạn vì đoạn mã này, có thể cung cấp một số trợ giúp hạn chế, ngay lập tức. Một lời giải thích phù hợp sẽ cải thiện đáng kể giá trị lâu dài của nó bằng cách chỉ ra lý do tại sao đây là một giải pháp tốt cho vấn đề và sẽ giúp nó hữu ích hơn cho những người đọc tương lai với những câu hỏi tương tự khác. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số giải thích, bao gồm các giả định bạn đã thực hiện.
Abdelilah El Aissaoui
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.