Làm thế nào để có được một Đoạn để loại bỏ chính nó, tức là tương đương với kết thúc ()?


230

Tôi đang chuyển đổi một ứng dụng để sử dụng các đoạn bằng thư viện tương thích. Hiện tại tôi có một số hoạt động (ABCD) nối tiếp nhau, D có nút 'OK' mà khi nhấn cuộc gọi kết thúc, sau đó bong bóng lênonActivityResult() để phá hủy thêm C và B.

Đối với phiên bản phân đoạn Honycomb trước của tôi, mỗi hoạt động thực sự là một trình bao bọc trên các phân đoạn Af Bf Cf Df. Tất cả các hoạt động được đưa ra thông qua startActivityForResult()onActivityResult() trong mỗi phân đoạn có thể vui vẻ gọigetActivity().finish()

Vấn đề mà tôi gặp phải là trong phiên bản Honeycomb của tôi, tôi chỉ có một hoạt động, A và các đoạn Bf, Cf, Df được tải bằng cách sử dụng FragmentManager .

Điều tôi không hiểu là phải làm gì trong Df khi nhấn 'OK' để xóa các đoạn Df, Cf và Bf?

Tôi đã cố gắng để mảnh vỡ tự bật ra khỏi ngăn xếp nhưng điều này dẫn đến một ngoại lệ. onActivityResult()là vô ích vì tôi đã không tải lên đoạn bằng cách sử dụngstartActivityForResult() .

Tôi đang nghĩ về điều này hoàn toàn sai cách? Tôi có nên thực hiện một số loại trình nghe giao tiếp với phân đoạn cha mẹ hoặc hoạt động để thực hiện pop bằng trình quản lý giao dịch không?


7
những gì về ((YourActivity) getActivity ()). onBackPression ();
Viswanath Lekshmanan 10/03/2015

@ViswanathLekshmanan câu trả lời nhận xét của bạn rất hữu ích cho tôi .. 1 Upvote từ tôi
Abhishek Singh

@AbhishekSingh Thật tốt khi nghe :)
Viswanath Lekshmanan

@ViswanathLekshmanan :)
Abhishek Singh

Câu trả lời:


62

Điều tôi không hiểu là phải làm gì trong Df khi nhấn 'OK' để xóa các đoạn Df, Cf và Bf?

Bước # 1: Yêu cầu Df nói với D "yo! Chúng tôi đã nhấp OK!" thông qua việc gọi một phương thức, trên chính hoạt động hoặc trên một cá thể giao diện được cung cấp bởi hoạt động.

Bước # 2: Yêu cầu D loại bỏ các đoạn thông qua FragmentManager.

Hoạt động lưu trữ (D) là hoạt động biết những đoạn khác trong hoạt động (so với hoạt động khác). Do đó, các sự kiện trong đoạn có thể ảnh hưởng đến hỗn hợp mảnh nên được truyền bá vào hoạt động, điều này sẽ tạo ra các bước di chuyển thích hợp.


Nhưng trong phiên bản Honeycomb của tôi không có D, đó là điều khó khăn của tôi. Đơn giản là có một activiy A tải Bf đoạn, tải Cf, tải Df bằng FragmentTransaction.
PJL

1
@PJL: Xin lỗi, ý tôi là A. Đây là một lý do để sử dụng giao diện người nghe, vì vậy nhiều hoạt động có thể đáp ứng với sự kiện "chúng tôi đã nhấp OK" từ Df.
CommonsWare

1
Như tôi hiện đang chuyển, tôi đã gọi một phương thức nghe từ các đoạn của phương thức Df's onActivityResult vào hoạt động mà sau đó tôi gọi là popBackStack trên FragmentManager. Tuy nhiên, điều này dẫn đến một sự miễn trừ "IllegalStateException: Không thể thực hiện hành động này sau khi onSaveInstanceState '. Bạn có ý tưởng nào về cách tôi có thể khắc phục điều này không?
PJL

1
@DiegoPalomar: finish()nên đủ.
CommonsWare

1
@ user3364963: Đã một thời gian kể từ khi tôi điều tra, nhưng IIRC, nó bị phá hủy khi nó được bật ra khỏi ngăn xếp phía sau. Thêm một onDestroy()phương thức vào đoạn của bạn và xem nếu nó được gọi.
CommonsWare

313

Mặc dù nó có thể không phải là cách tiếp cận tốt nhất tương đương gần nhất nhưng tôi có thể nghĩ rằng nó hoạt động với thư viện hỗ trợ / tương thích

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

hoặc là

getActivity().getFragmentManager().beginTransaction().remove(this).commit();

nếu không thì.

Ngoài ra, bạn có thể sử dụng backstack và bật nó. Tuy nhiên, hãy nhớ rằng mảnh vỡ có thể không nằm ở backstack (tùy thuộc vào sự phân mảnh đã có nó ở đó ..) hoặc nó có thể không phải là mảnh cuối cùng được xếp vào ngăn xếp để popping ngăn xếp có thể loại bỏ sai ...


11
Trong khi phương pháp này hoạt động, nếu bạn đang sử dụng addToBackStack (null), nó sẽ để lại trình xử lý nút quay lại +1. Vì vậy, bạn sẽ phải nhấn nó hai lần.
dùng123321

34
"bật" đoạn từ FragmentManager.
dùng123321

2
Tôi đã thử quy trình trên nhưng nó đang đưa ra lỗi này "java-lang-lawstateexception-can-not-Performance-this-action-after-onsaveinstance". Vì vậy, nơi chính xác tôi phải loại bỏ đoạn
KK_07k11A0585

6
Câu trả lời này là một thực tiễn xấu và không nên nhận được phiếu bầu. Những mảnh vỡ không có nghĩa là tự nhận thức như thế này. Nó giết chết khả năng sử dụng lại, đó là điểm của các mảnh vỡ! Đoạn này sẽ báo hiệu hoạt động để loại bỏ nó thông qua bất kỳ số lượng phương tiện. Phương thức giao diện gọi lại là một lựa chọn phổ biến. developer.android.com/training/basics/fragments/ từ
colintheshots

2
@ManfredMoser Tôi không đồng ý. Đây là rất nhiều điểm của câu hỏi. Anh ta có một chuỗi các mảnh vỡ để loại bỏ. Mã này không có kiểm tra hoặc kiểm tra null cho dù hoạt động được đính kèm. Nó sẽ bị phá vỡ trong sản xuất vì nó phụ thuộc vào quá nhiều thứ mà một mảnh không biết.
colintheshots

263

Bạn có thể sử dụng cách tiếp cận dưới đây, nó hoạt động tốt:

getActivity().getSupportFragmentManager().popBackStack();

44
Câu trả lời này giống như tốt hơn 10 lần so với câu trả lời được chấp nhận - đi thẳng vào vấn đề.
nikib3ro

50
Nó cũng tệ hơn 10 lần so với thiết kế so với thiết kế được chấp nhận. Một mảnh được cho là một "người trợ giúp" nhỏ cho một hoạt động và không bao giờ nên kiểm soát chính nó hoặc các mảnh khác
Patrick

6
Giải pháp không đúng như @avalancha đã chỉ ra. Có một cái nhìn về developer.android.com/guide/components/
Kẻ

2
Tôi đang sử dụng phương thức này trênActivityResult và gặp lỗi "Không thể thực hiện hành động này sau khi onSaveInstanceState". Làm thế nào tôi có thể giải quyết nó?
Jayeshkumar Sojitra

1
popBackStack()là giải pháp duy nhất hoạt động khi bạn muốn đặt tiêu đề thanh hành động trở lại trạng thái trước đó sau khi bạn xóa đoạn. Mặt khác, tôi không cần kết hợp cả hai giải pháp được xếp hạng cao từ stackoverflow.com/questions/13472258/ và giải pháp này ở đây để luôn đặt tiêu đề thanh hành động phù hợp sau nhiều trường hợp sử dụng. như nhấn lại, xóa, thêm thay thế, v.v.
Bevor 15/03/2016

36

Bạn nên để Activity xử lý việc thêm và xóa các đoạn, như CommonsWare nói, hãy sử dụng trình nghe. Đây là một ví dụ:

public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {

    // onCreate etc

    @Override
    public void onFragmentSuicide(String tag) {
        // Check tag if you do this with more than one fragmen, then:
        getSupportFragmentManager().popBackStack();
    }
}

public interface SuicidalFragmentListener {
    void onFragmentSuicide(String tag);
}

public class MyFragment extends Fragment {

    // onCreateView etc

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
           suicideListener = (SuicidalFragmentListener) activity;
        } catch (ClassCastException e) {
           throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Attach the close listener to whatever action on the fragment you want
        addSuicideTouchListener();
    }

    private void addSuicideTouchListener() {
        getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              suicideListener.onFragmentSuicide(getTag());
            }
        });
    }
}

5
Tự tử nhiều kiểu emo? Làm thế nào về "Tự đóng" hoặc "Tự động đóng" hoặc "Đóng thông minh" (r)
DritanX

21
nó không đóng cửa mà nó KHÔNG BAO GIỜ ;-(
Blundell

3
Đây là một cách tiếp cận sạch hơn nhiều so với các câu trả lời khác. Các hoạt động tạo và trình bày các mảnh, và nên kiểm soát vòng đời của nó. Khi một cái gì đó xảy ra chỉ ra đoạn không còn trong tầm nhìn, nó sẽ báo cho Activity biết và để cho hoạt động loại bỏ nó.
Christopher Pickslay

7
Về mặt kỹ thuật, nếu chúng ta phải có hoạt động tiêu diệt mảnh vỡ, thì mảnh vỡ đó không phải là tự sát. Các hoạt động là sát nhân.
Casey Murray

17

Trong Activity / AppCompatActivity:

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        // if you want to handle DrawerLayout
        mDrawerLayout.closeDrawer(GravityCompat.START);
    } else {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            super.onBackPressed();
        } else {
            getFragmentManager().popBackStack();
        }
    }
}

và sau đó gọi trong đoạn:

getActivity().onBackPressed();

hoặc như đã nêu trong các câu trả lời khác, hãy gọi nó trong đoạn:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

5

Nếu bạn đang sử dụng Thành phần điều hướng mới, thì đơn giản như

findNavController().popBackStack()

Nó sẽ thực hiện tất cả các FragmentTransaction phía sau cho bạn.


4

Xem nếu nhu cầu của bạn được đáp ứng bởi DialogFragment. DialogFragment có một phương thức notify (). Theo tôi thì sạch sẽ hơn nhiều.


3

Tôi tạo phương thức đơn giản cho việc đó

popBackStack(getSupportFragmentManager());

Hơn đặt nó trong lớp ActivityUtils của tôi

public static void popBackStack(FragmentManager manager){
        FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
        manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

Đó là công việc tuyệt vời, vui chơi!


2
Tôi không hiểu mục đích của phương pháp của bạn. PopBackStack ban đầu có vẻ hoàn toàn đầy đủ.
Không thể tin được vào

1

OnCreate:

//Add comment fragment
            container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
            mPictureFragment = new fmtAttachPicture();

            var trans = SupportFragmentManager.BeginTransaction();
            trans.Add(container.Id, mPictureFragment, "fmtPicture");
            trans.Show(mPictureFragment); trans.Commit();

Đây là cách tôi ẩn đoạn trong sự kiện nhấp 1

//Close fragment
    var trans = SupportFragmentManager.BeginTransaction();
    trans.Hide(mPictureFragment);
    trans.AddToBackStack(null);
    trans.Commit();

Sau đó hiển thị lại sự kiện int 2

var trans = SupportFragmentManager.BeginTransaction();
            trans.Show(mPictureFragment); trans.Commit();

1

Nếu bạn cần bật lại từ đoạn thứ tư trong lịch sử backstack sang đoạn đầu tiên, hãy sử dụng thẻ !!!

Khi bạn thêm đoạn đầu tiên, bạn nên sử dụng một cái gì đó như thế này:

getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit() 

hoặc là

getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()

Và khi bạn muốn hiển thị các đoạn B, C và D, bạn sử dụng:

getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()

và các chữ cái khác ....

Để trở về FragmentA, chỉ cần gọi popBackStack(0, "A"), vâng, sử dụng cờ mà bạn đã chỉ định khi thêm nó và lưu ý rằng nó phải là cùng một cờ trong lệnhaddToBackStack() , không được sử dụng trong lệnh thay thế hoặc thêm.

Không có gì ;)


Tôi đã thử nghiệm 'popBackStack (0, "A")' và ứng dụng của tôi quay lại đoạn A, nhưng tôi muốn chỉ đoạn đó sẽ bị xóa khỏi Back Stack ... Làm cách nào tôi có thể xóa đoạn khỏi Stack mà không hiển thị trên màn hình ??
KryNaC

1

Để đóng một đoạn trong khi bên trong cùng một đoạn

getActivity().onBackPressed();

-9

Tại sao không chỉ:

getActivity (). finish ();


4
Điều này sẽ kết thúc toàn bộ hoạt động không chỉ là đoạn.
Murtadha S.
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.