原始碼問題在於:AlertDialog.Builder 的 show() 回傳 AlertDialog,但範例沒存起來,導致無法在 onItemClick 內關閉。
public void showSearchDialog(String[] memos) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = LayoutInflater.from(this).inflate(R.layout.seach_dialog, null);
ListView listView = view.findViewById(R.id.search_list);
listView.setAdapter(new MyPerformanceArrayAdapter(this, memos, memo_PW));
// 建立並持有 Dialog 實例
AlertDialog dialog = builder
.setTitle("Search")
.setView(view)
.setNegativeButton("Back", null)
.create(); // 用 create() 不用 show()
listView.setOnItemClickListener((parent, v, position, id) -> {
// 處理點選邏輯...
dialog.dismiss(); // 關鍵:持有的 dialog 實例呼叫 dismiss()
});
dialog.show(); // 最後才 show
}
Activity 旋轉重建時,手持 AlertDialog 易洩漏視窗。建議改用 DialogFragment:
public class SearchDialogFragment extends DialogFragment {
private String[] memos;
public static SearchDialogFragment newInstance(String[] memos) {
SearchDialogFragment f = new SearchDialogFragment();
f.memos = memos;
return f;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = LayoutInflater.from(requireContext()).inflate(R.layout.seach_dialog, null);
ListView lv = view.findViewById(R.id.search_list);
lv.setAdapter(new MyPerformanceArrayAdapter(requireContext(), memos, null));
lv.setOnItemClickListener((p, v, pos, id) -> {
// 回傳結果給宿主
((OnSearchSelected) requireActivity()).onSelected(memos[pos]);
dismiss(); // 安全關閉
});
return new AlertDialog.Builder(requireContext())
.setTitle("Search")
.setView(view)
.setNegativeButton("Back", null)
.create();
}
public interface OnSearchSelected { void onSelected(String memo); }
}
使用方式:SearchDialogFragment.newInstance(memos).show(getSupportFragmentManager(), "search")。
onItemClick 裡 new AlertDialog.Builder(...).show() 建立新對話框 → 無法關閉原本那個。dismiss() vs cancel():dismiss() 直接關閉;cancel() 會觸發 OnCancelListener,語意上「使用者取消」才用 cancel。WindowLeaked → 改用 DialogFragment 徹底解決。**持有 Dialog 實例 → 在 onItemClick 呼叫 dismiss()** 是最直接解法;專案若重視生命週期安全,**直接上 DialogFragment** 才是長久之計。