Làm cách nào để loại bỏ chính xác một DialogFragment?


121

Các tài liệu nói điều này cho dismiss()phương thức từ Dialoglớp:

Loại bỏ hộp thoại này, xóa hộp thoại khỏi màn hình. Phương thức này có thể được gọi một cách an toàn từ bất kỳ luồng nào. Lưu ý rằng bạn không nên ghi đè phương pháp này để thực hiện dọn dẹp khi hộp thoại bị loại bỏ, thay vào đó hãy triển khai phương thức đó trong onStop().

Trong mã của tôi, tất cả những gì tôi làm là gọi getDialog().dismiss()để loại bỏ nó. Nhưng tôi không làm bất cứ điều gì khác hoặc thậm chí sử dụng onStop(). Vì vậy, tôi đang hỏi chính xác cách loại bỏ chính xác một DialogFragmentđể tránh bất kỳ rò rỉ bộ nhớ nào, v.v.

Câu trả lời:


197

tl; dr: Cách chính xác để đóng a DialogFragmentlà sử dụng dismiss() trực tiếp trên DialogFragment .


Chi tiết : Tài liệu về trạng thái DialogFragment

Việc kiểm soát hộp thoại (quyết định thời điểm hiển thị, ẩn, loại bỏ nó) nên được thực hiện thông qua API ở đây, không phải với các lệnh gọi trực tiếp trên hộp thoại.

Vì vậy, bạn không nên sử dụng getDialog().dismiss(), vì điều đó sẽ gọi dismiss() trên hộp thoại . Thay vào đó, bạn nên sử dụng dismiss()phương thức của chính DialogFragment:

bãi bỏ công khai ()

Loại bỏ phân đoạn và hộp thoại của nó. Nếu phân đoạn được thêm vào ngăn xếp phía sau, tất cả trạng thái ngăn xếp phía sau lên đến và bao gồm mục nhập này sẽ được bật lên. Nếu không, một giao dịch mới sẽ được cam kết để loại bỏ phân mảnh.

Như bạn có thể thấy, điều này không chỉ quan tâm đến việc đóng hộp thoại mà còn xử lý các giao dịch phân mảnh liên quan đến quy trình.

Bạn chỉ cần sử dụng onStopnếu bạn đã tạo rõ ràng bất kỳ tài nguyên nào yêu cầu dọn dẹp thủ công (đóng tệp, đóng con trỏ, v.v.). Ngay cả khi đó, tôi sẽ ghi đè onStopDialogFragment thay vì onStopHộp thoại bên dưới.


1
@ScootrNova: Không nên đâu, bạn có thể gặp lỗi ở nơi khác. Bạn đang tạo mảnh vỡ như thế nào?
Heinzi

protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Xin lỗi vì một lớp lót khó chịu! Nhưng vâng, bạn có thể đúng, vì vậy tạm thời tôi đã viết ra một cách khác để đóng DialogFragment của mình. Cách mà tôi loại bỏ chúng bằng cách sử dụng phương thức miễn phí () chỉ là tìm kiếm phân đoạn theo thẻ và sau đó chạy thẻ bỏ qua () trên đó nếu nó không phải là null. Ồ và đúng vậy, tôi đang newnhập phân đoạn ngay trước khi chuyển nó sang phương thức đó.
Charles Madere

2
@ScootrNova: Hmm, không thấy có gì sai với điều đó - mặt khác, tôi chưa bao giờ sử dụng thư viện tương thích, vì vậy tôi không thể chắc chắn về điều đó. Có lẽ bạn nên tạo một ví dụ tối thiểu, khép kín và bắt đầu một câu hỏi mới về vấn đề đó.
Heinzi

@CharlesMadere trong những ngày đó, bạn đã tìm ra giải pháp chưa?
JCarlosR

Xin lỗi @JCarlos, đây là năm trước, tôi không chắc.
Charles Madere,

76

Tôi nghĩ rằng một cách tốt hơn để đóng một DialogFragmentlà sau:

Fragment prev = getSupportFragmentManager().findFragmentByTag("fragment_dialog");
if (prev != null) {
    DialogFragment df = (DialogFragment) prev;
    df.dismiss();
}

Bằng cách này, bạn không phải giữ một tham chiếu đến DialogFragmentvà có thể đóng nó từ mọi nơi.


7

Tại sao bạn không thử chỉ sử dụng mã này:

dismiss();

Nếu bạn muốn tự loại bỏ Phân mảnh hộp thoại. Bạn có thể chỉ cần đặt mã này bên trong phân đoạn hộp thoại mà bạn muốn loại bỏ Hộp thoại.

Ví dụ:

button.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       dismiss();
   }
});

Thao tác này sẽ đóng Phân đoạn hộp thoại gần đây được hiển thị trên màn hình.

Hy vọng nó sẽ giúp ích cho bạn.


không làm việc mọi lúc
Mahmoud Heretani

5

Tôi đã ủng hộ câu trả lời của Terel. Tôi chỉ muốn đăng bài này cho bất kỳ người dùng Kotlin nào:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}

Mã đơn giản hoạt động chăm chỉ, Cảm ơn bạn đã cập nhật !!
Ayush Katuwal

4

Kotlin Phiên bản của câu trả lời Terel

(fragmentManager.findFragmentByTag(TAG) as? DialogFragment)?.dismiss()

1

Bạn nên bỏ bạn Dialogtrong onPause()quá ghi đè lên nó.

Ngoài ra, trước khi loại bỏ, bạn có thể kiểm tra nullvà hiển thị như đoạn mã dưới đây:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}

anh ấy đã viết rằng anh ấy đang làm bỏ qua () và nó về DialogFragment.
Paresh Mayani

Tôi nghĩ tác phẩm này cho cả Dialog và DialogFragments @PareshMayani
Venky

2
Tôi tin rằng @PareshMayani là đúng Venky. Hướng dẫn DialogFragmentcủa google hoàn toàn không hiển thị onPause()phương pháp đang được sử dụng. Nhưng tôi nghĩ tôi thấy những gì bạn đang làm. Tuy nhiên, vấn đề là gì nếu người dùng không gọi onPause(). Đó là khi hệ thống biết phân đoạn đang được gọi đi. Còn khi nào thì người dùng hủy bỏ. Có cách nào tốt hơn để đóng nó trong trường hợp đó?
Andy

1

Có các tham chiếu đến tài liệu chính thức ( Tham chiếu DialogFragment ) trong các câu trả lời khác, nhưng không đề cập đến ví dụ được cung cấp ở đó:

void showDialog() {
    mStackLevel++;

    // DialogFragment.show() will take care of adding the fragment
    // in a transaction.  We also want to remove any currently showing
    // dialog, so make our own transaction and take care of that here.
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment prev = getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    // Create and show the dialog.
    DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
    newFragment.show(ft, "dialog");
}

Thao tác này loại bỏ bất kỳ hộp thoại nào hiện được hiển thị, tạo DialogFragment mới với một đối số và hiển thị nó dưới dạng trạng thái mới trên ngăn xếp phía sau. Khi giao dịch được bật lên, DialogFragment hiện tại và Hộp thoại của nó sẽ bị hủy và phần trước đó (nếu có) được hiển thị lại. Lưu ý rằng trong trường hợp này DialogFragment sẽ xử lý việc bật giao dịch của Hộp thoại bị loại bỏ riêng biệt với nó.

Vì nhu cầu của tôi, tôi đã thay đổi nó thành:

FragmentManager manager = getSupportFragmentManager();
Fragment prev = manager.findFragmentByTag(TAG);
if (prev != null) {
    manager.beginTransaction().remove(prev).commit();
}

MyDialogFragment fragment = new MyDialogFragment();
fragment.show(manager, TAG);

1

Thêm vào các câu trả lời khác, khi có một DialogFragmentcuộc gọi ở chế độ toàn màn hình dismiss()sẽ không bật DialogFragment khỏi ngăn xếp mảnh. Một cách giải quyết là gọi onBackPressed()hoạt động mẹ.

Một cái gì đó như thế này:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}

Tiết kiệm một ngày, cảm ơn rất nhiều
Mahmoud Heretani

0

Chỉ cần gọi bỏ qua () từ đoạn bạn muốn loại bỏ.

imageView3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dismiss();
        }
    });

0

Tôi nhận thấy rằng khi phân đoạn của tôi được xác định trong biểu đồ điều hướng bằng <fragment>thẻ (đối với phân đoạn hộp thoại toàn màn hình), phân đoạn hộp thoại sẽ không loại bỏ bằng dismiss()lệnh. Thay vào đó, tôi phải bật ngăn xếp trở lại:

findNavController(getActivity(), R.id.nav_host_fragment).popBackStack();

Tuy nhiên, nếu cùng một phân đoạn hộp thoại được xác định trong biểu đồ điều hướng với một <dialog>thẻ, dismiss()hoạt động tốt.


0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}
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.