Đây có phải là cách thích hợp để dọn sạch ngăn xếp mảnh vỡ trở lại khi để lại một ngăn xếp lồng sâu?


130

Tôi đang sử dụng thư viện Tương thích Android để triển khai các đoạn và đã mở rộng mẫu bố cục sao cho một đoạn có chứa nút bật ra một đoạn khác.

Trong khung lựa chọn bên trái tôi có 5 mục có thể chọn - A B C D E.

Mỗi phần tải lên một đoạn (thông qua FragmentTransaction:replace) trong khung chi tiết -a b c d e

Bây giờ tôi đã mở rộng đoạn eđể chứa một nút tải lên một đoạn khác e1trong khung chi tiết. Tôi đã thực hiện điều này trên ephương pháp onClick của đoạn như sau:

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

Nếu tôi thực hiện các lựa chọn sau:

E - e - e1 - D - E

Sau đó, đoạn enằm trong khung chi tiết. Điều này là tốt và những gì tôi muốn. Tuy nhiên, nếu tôi nhấn backnút vào thời điểm này thì không có gì. Tôi phải bấm vào nó hai lần vì e1vẫn còn trên stack. Hơn nữa, sau khi nhấp vào xung quanh tôi đã có một ngoại lệ con trỏ null trong onCreateView:

Để 'giải quyết' vấn đề này, tôi đã thêm vào bất cứ khi nào A B C D Eđược chọn:

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

Chỉ tự hỏi liệu đây là giải pháp chính xác hay liệu tôi nên làm điều gì đó khác biệt?

Câu trả lời:


252

Vâng, có một vài cách để giải quyết vấn đề này tùy thuộc vào hành vi dự định, nhưng liên kết này sẽ cung cấp cho bạn tất cả các giải pháp tốt nhất và không ngạc nhiên là từ Dianne Hackborn

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

Về cơ bản, bạn có các tùy chọn sau

  • Sử dụng tên cho trạng thái ngăn xếp trở lại ban đầu của bạn và sử dụng FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Sử dụng FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() để lấy ID của mục nhập đầu tiên trên ngăn xếp phía sau và FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) được cho là bật toàn bộ ngăn xếp phía sau ... Tôi nghĩ rằng tài liệu cho điều đó là sai. (Trên thực tế tôi đoán nó chỉ không bao gồm trường hợp bạn đi qua POP_BACK_STACK_INCLUSIVE),

Điều đó có nghĩa là gì? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). GetId ()
dannyroa

4
2 làm việc cho tôi. Ý nghĩa của việc xóa toàn bộ ngăn xếp: getSupportFragmentManager (). PopBackStack (getSupportFragmentManager (). GetBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL

@JorgeGarcia là có thể sau khi popbackstack chúng tôi chỉ hoàn thành đoạn của chúng tôi mà không cần khởi động lại cái cũ.
duggu

Xin lưu ý rằng đó cũng là phiên bản popBackStackImmediate () vì popBackStack () không đồng bộ, có nghĩa là việc xóa không xảy ra tại thời điểm chính xác mà bạn gọi phương thức.
Genc

6
Khẳng định nhóm bị cấm là spam và tôi không thể truy cập vào liên kết :( có ai có tài nguyên ở nơi khác không?
EpicPandaForce

61

Giải pháp sạch khác nếu bạn không muốn bật tất cả các mục ngăn xếp ...

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

Điều này sẽ làm sạch ngăn xếp trước và sau đó tải một đoạn mới, vì vậy tại bất kỳ thời điểm nào, bạn sẽ chỉ có một đoạn duy nhất trong ngăn xếp


1
Đây là rất xấu: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);trước khi thay thế () vì đang tải kêu gọi Fragment onCreateView(), onActivityCreated()vv Phục hồi và Destroing một Fragment ngay lập tức là xấu. Fragment có thể đăng ký một người nhận chẳng hạn. Điều này ảnh hưởng đến hiệu suất.
VasileM

@VasileM, bạn có thể mô tả chi tiết không? Trong trường hợp nào nó là xấu? Có phải vì hành vi asynhronous của FragmentTransaction? Có phải chỉ có hiệu suất xấu của ngăn xếp mảnh sai?
CoolMind

27

Nhờ câu trả lời của Joachim , tôi sử dụng mã để xóa tất cả các mục nhập ngăn xếp cuối cùng.

// 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
Tại sao sử dụng một vòng lặp ở đây? Đối với tôi FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) đã xóa tất cả mục nhập ngăn xếp trở lại ...
Marek

3
@Marek, vì đôi khi không phải loại bỏ tất cả các mảnh vỡ, một vòng lặp phù hợp cho việc này.
CoolMind

1
@CoolMind, điều đó vẫn không có ý nghĩa với tôi. popBackStack(backStackId, INCLUSIVE)sẽ bật tất cả các đoạn (trạng thái) trở lại backStackId, vì vậy một khi bạn bật mức thấp nhất imà bạn sẽ bật, tất cả các đoạn cao hơn sẽ được bật cùng một lúc. Vì vậy, điểm của một vòng lặp là gì?
LarsH

@LarsH, bạn nói đúng. Xem stackoverflow.com/a/59158254/2914140 . Để bật các đoạn khác vào thẻ yêu cầu, trước tiên chúng ta nên thêm đoạn đó bằng addToBackStack ( thẻ ).
CoolMind

7

Tôi đã nghiên cứu rất nhiều để làm sạch Backstack, và cuối cùng thấy Giao dịch BackStack và quản lý của nó . Đây là giải pháp làm việc tốt nhất cho tôi.

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

Phương thức trên lặp lại tất cả các giao dịch trong backstack và loại bỏ chúng ngay lập tức một lần.

Lưu ý: mã ở trên đôi khi không hoạt động và tôi phải đối mặt với ANR vì mã này, vì vậy vui lòng không thử mã này.

Cập nhật phương pháp bên dưới loại bỏ tất cả sự tự do của "tên" đó từ backstack.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • tên Nếu không có giá trị, đây là tên của trạng thái quay lại trước đó cần tìm; nếu được tìm thấy, tất cả các trạng thái cho đến trạng thái đó sẽ được bật lên. Các
  • Cờ POP_BACK_STACK_INCLUSIVE có thể được sử dụng để kiểm soát xem chính trạng thái được đặt tên có được bật hay không. Nếu null, chỉ trạng thái trên cùng được bật.

Tôi không thấy lý do tại sao bạn sẽ loại bỏ chúng cùng một lúc. Có một lý do tại sao bạn chọn giải pháp này thay vì các giải pháp khác? Có một lý do để loại bỏ chúng cùng một lúc thay vì tất cả cùng một lúc?
miva2

Không có phương pháp nào để loại bỏ backstack cùng một lúc, hãy xem developer.android.com/reference/android/app/
Lokesh

3

Tôi đang sử dụng một mã tương tự như các mã sử dụng vòng lặp while nhưng tôi gọi số lượng mục nhập trong mỗi vòng lặp ... vì vậy tôi cho rằng nó hơi chậm hơn

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

0

Như được viết trong Làm thế nào để bật mảnh vỡ ra khỏi backstack và bởi LarsH ở đây, chúng ta có thể bật một số đoạn từ trên xuống đến thẻ cụ thể ( cùng với đoạn được gắn thẻ ) bằng phương pháp này:

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

Thay thế "Frag" bằng thẻ của đoạn của bạn. Hãy nhớ rằng trước tiên chúng ta nên thêm đoạn vào backstack với:

fragmentTransaction.addToBackStack("frag")

Nếu chúng ta thêm các mảnh với addToBackStack(null), chúng ta sẽ không bật các mảnh đó theo cách đó.


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
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.