在 Android 開發中,使用 AlertDialog.Builder 的 setView() 方法載入自訂佈局時,常會遇到 NullPointerException 錯誤。這通常是因為嘗試在錯誤的視圖層級中查找元件所導致。
以下代碼會在 MyTextView.setText("test") 行拋出空指針異常:
LayoutInflater inflater = LayoutInflater.from(this);
View layout = inflater.inflate(R.layout.mylayout, null);
TextView MyTextView = (TextView) findViewById(R.id.my_tv); // 錯誤寫法
MyTextView.setText("test");
AlertDialog MyDialog;
AlertDialog.Builder MyBuilder = new AlertDialog.Builder(this);
MyBuilder.setTitle("title");
MyBuilder.setView(layout);
MyDialog = MyBuilder.create();
MyDialog.show();
findViewById() 預設在當前 Activity 的佈局中查找視圖,但 my_tv 實際上位於剛剛 inflate 出來的 layout 視圖中,而非 Activity 的主佈局。這就像把東西放在房間 A,卻跑到房間 B 找一樣,自然找不到。
必須在 inflate 出來的 layout 視圖上調用 findViewById():
TextView MyTextView = (TextView) layout.findViewById(R.id.my_tv);
LayoutInflater inflater = LayoutInflater.from(this);
View layout = inflater.inflate(R.layout.mylayout, null);
// 關鍵修正:在 layout 視圖中查找元件
TextView MyTextView = (TextView) layout.findViewById(R.id.my_tv);
MyTextView.setText("test");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("標題");
builder.setView(layout);
AlertDialog dialog = builder.create();
dialog.show();
記住一個簡單原則:視圖元件在哪個佈局容器中,就必須在該容器的視圖物件上調用 findViewById()。這不僅適用於對話框,也適用於 Fragment、ListView 項目佈局、RecyclerView ViewHolder 等所有動態載入佈局的場景。