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

Android ListView 點擊 EditText 觸發 BaseAdapter getView 的原因分析

     編輯:程式設計綜合問答

問題現象

ListView 中包含 EditText,點擊 EditText 時 BaseAdapter.getView() 被重複調用,導致界面閃爍、數據重置等異常。

根本原因

ListView 佈局重渲染機制:

  1. EditText 獲得焦點 → 軟鍵盤彈出
  2. 窗口大小變化 → ListView 重新佈局
  3. ListView 為了適應新高度,重新測量、佈局所有可見項
  4. 觸發 getView() 重新綁定視圖

次要原因

  • getView() 實現不當:未正確使用 convertView 復用、未使用 ViewHolder 模式
  • 數據源在 getView() 中被修改(如代碼中 vh.createDate.setText(chatMessage.getContent()) 疑似邏輯顛倒)
  • 未設置 android:descendantFocusability 控制焦點行為

解決方案

方案一:設置 ListView 焦點策略(最簡單)

<ListView
    android:id="@+id/listView1"
    android:descendantFocusability="beforeDescendants"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  • beforeDescendants:ListView 先獲取焦點,子 View 再獲取,減少重渲染
  • afterDescendants:子 View 優先(默認)
  • blocksDescendants:阻塞子 View 獲取焦點(ListView 不可編輯時用)

方案二:Activity 窗口模式調整

<activity
    android:name=".MainActivity"
    android:windowSoftInputMode="adjustPan|stateHidden" />
  • adjustPan:窗口平移而非壓縮,避免 ListView 重新佈局
  • stateHidden:默認隱藏軟鍵盤

方案三:優化 getView 實現(必須)

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder vh;
    if (convertView == null) {
        convertView = inflater.inflate(layoutId, parent, false);
        vh = new ViewHolder(convertView);
        convertView.setTag(vh);
    } else {
        vh = (ViewHolder) convertView.getTag();
    }
    
    Msg msg = mDatas.get(position);
    // 僅綁定數據,不修改數據源!
    vh.createDate.setText(msg.getDateStr());  // 修正:顯示日期
    vh.content.setText(msg.getContent());     // 修正:顯示內容
    return convertView;
}

方案四:使用 RecyclerView 替代(現代方案)

  • RecyclerView 強制 ViewHolder 模式
  • 項目動畫可控,預設不會因鍵盤彈出全量重綁
  • 配合 notifyItemChanged(position, payload) 實現局部刷新

代碼中發現的邏輯錯誤

vh.createDate.setText(chatMessage.getContent()); // 錯:日期欄顯示內容
vh.content.setText(chatMessage.getDateStr());    // 錯:內容欄顯示日期

應交換為:

vh.createDate.setText(chatMessage.getDateStr());
vh.content.setText(chatMessage.getContent());

總結

點擊 EditText 觸發 getView() 是 ListView 重佈局機制導致。綜合採用 descendantFocusability、windowSoftInputMode=adjustPan、優化 getView() 復用邏輯、修正數據綁定錯誤,可徹底解決。長期建議遷移至 RecyclerView。

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