首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android AlertDialog 彈出後啟動新 Activity 導致 Window Leaked 解決方案

     編輯:程式設計綜合問答

錯誤現象

Activity AActivity has leaked window ... DecorView@... that was originally added here

原因:AlertDialog 依附於 Activity 窗口,當 Dialog 顯示時啟動新 Activity (startActivity),舊 Activity 進入停止狀態,但 Dialog 未關閉,導致窗口洩漏。

核心解決原則

在 Activity 失去焦點/銷毀前,必須關閉 Dialog。

方案一:在 Dialog 按鈕點擊中啟動新 Activity 並關閉 Dialog


AlertDialog dialog = new AlertDialog.Builder(this)
    .setTitle("重命名")
    .setView(editText)
    .setPositiveButton("確定", (dialogInterface, which) -> {
        // 1. 獲取輸入
        String newName = editText.getText().toString();
        // 2. 關閉 Dialog (隱式調用 dismiss)
        // 3. 啟動新 Activity
        Intent intent = new Intent(AActivity.this, BActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
    })
    .setNegativeButton("取消", null)
    .create();
dialog.show();

**關鍵**:在 PositiveButton 的 onClick 中先處理邏輯,再 startActivity。Dialog 會自動 dismiss。

方案二:在 Activity 生命周期中統一管理 Dialog


private AlertDialog renameDialog;

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

@Override
protected void onPause() {
    super.onPause();
    // 可選:Activity 不可見時關閉 Dialog
    if (renameDialog != null && renameDialog.isShowing()) {
        renameDialog.dismiss();
    }
}

方案三:使用 DialogFragment (現代推薦)

DialogFragment 自動管理生命周期,配合 FragmentManager 可在配置變更、Activity 重建時保持狀態:


public class RenameDialogFragment extends DialogFragment {
    public static RenameDialogFragment newInstance(String currentName) {
        Bundle args = new Bundle();
        args.putString("name", currentName);
        RenameDialogFragment f = new RenameDialogFragment();
        f.setArguments(args);
        return f;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final EditText input = new EditText(getActivity());
        input.setText(getArguments().getString("name"));
        
        return new AlertDialog.Builder(getActivity())
            .setTitle("重命名")
            .setView(input)
            .setPositiveButton("確定", (dialog, which) -> {
                String newName = input.getText().toString();
                // 通過接口回調 Activity
                ((OnRenameListener) getActivity()).onRenameConfirmed(newName);
            })
            .setNegativeButton("取消", null)
            .create();
    }
    
    public interface OnRenameListener {
        void onRenameConfirmed(String newName);
    }
}

// Activity 中調用
RenameDialogFragment.newInstance(currentName)
    .show(getSupportFragmentManager(), "rename_dialog");

錯誤代碼修正對照

錯誤寫法問題修正
在 setOnClickListener 中 show() 後直接 startActivity()Dialog 未關閉,Activity 跳轉導致洩漏將 startActivity() 移入 Dialog 的 PositiveButton 回調中
未在 onDestroy/onPause 關閉 Dialog異常退出時洩漏生命周期中統一 dismiss()
直接用 AlertDialog生命周期管理困難遷移至 DialogFragment

總結

**Dialog 必須在依附的 Activity 可見時關閉**。最佳實踐:使用 DialogFragment 讓框架自動管理,或在按鈕回調/生命周期中顯式 dismiss() 後再跳轉 Activity。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved