Activity AActivity has leaked window ... DecorView@... that was originally added here
原因:AlertDialog 依附於 Activity 窗口,當 Dialog 顯示時啟動新 Activity (startActivity),舊 Activity 進入停止狀態,但 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。
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 自動管理生命周期,配合 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。