在 Android 開發中,許多初學者會嘗試在 Activity 中直接通過 findViewById 獲取 ExpandableListView 中 Child Item 內部的 Button,然後設置點擊監聽器實現頁面跳轉。但這種做法存在嚴重的邏輯缺陷。
ExpandableListView 的 Child Item 是動態複用的,同一個 Button 實例可能對應多組數據。如果在 Activity 中「獲取 Button」,到底獲取的是哪一個?這違背了列表視圖的複用機制,會導致不可預期的行為。
標準做法是在 ExpandableListAdapter 的 getChildView() 方法中,通過 convertView.findViewById() 獲取 Button,然後直接為其設置 OnClickListener。
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.child_item, parent, false);
}
Button button = convertView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 在這裡編寫跳轉邏輯
// 可通過 groupPosition、childPosition 確定具體數據
Intent intent = new Intent(context, TargetActivity.class);
context.startActivity(intent);
}
});
return convertView;
}
為了提升性能,建議採用 ViewHolder 模式避免重複 findViewById:
static class ChildViewHolder {
Button actionButton;
TextView titleText;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
ChildViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.child_item, parent, false);
holder = new ChildViewHolder();
holder.actionButton = convertView.findViewById(R.id.button);
holder.titleText = convertView.findViewById(R.id.title);
convertView.setTag(holder);
} else {
holder = (ChildViewHolder) convertView.getTag();
}
// 設置點擊事件
holder.actionButton.setOnClickListener(v -> {
// 處理點擊邏輯
});
return convertView;
}
如果確實需要在 Activity 中操作某個特定 Button(極少見),可使用 setTag() 標識:
getChildView 中:button.setTag("unique_tag_" + groupPosition + "_" + childPosition)Button btn = expandableListView.findViewWithTag("unique_tag_0_1")注意:此做法違背列表複用原則,僅作為特殊場景的應急方案,不建議常規使用。
getChildView() 中通過 convertView 獲取並設置監聽groupPosition、childPosition 區分具體數據項遵循這些原則,能避免空指針異常、數據錯亂等常見問題,編寫出穩健的 ExpandableListView 交互邏輯。