You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ListView内EditText失焦时用户输入被清空的原因排查

解决ListView中EditText焦点异常与内容丢失问题

你的问题根源在于ListView适配器的getView方法没有正确实现视图复用,同时输入内容未同步到数据源Model中,加上焦点管理不当,导致了焦点跳变和内容丢失。下面是具体的修复方案:

核心问题拆解

  • 视图完全未复用:每次调用getView都重新inflate布局,完全废弃了ListView的视图复用机制。滚动时旧视图被销毁重建,之前输入的内容自然丢失,焦点也会因视图重建出现异常。
  • 输入内容未持久化:EditText的输入只停留在View层面,没有更新到对应的ProductionLineModel对象中。重建视图时会从Model读取初始值,覆盖用户输入。
  • 临时状态未绑定到Model:非"GECLAIMED"分支里的PalletUpdated是局部数组,会被复用的视图共享,导致状态混乱。

修复步骤与代码示例

1. 实现ViewHolder模式复用视图

把视图引用缓存到ViewHolder中,避免重复findViewById和inflate:

static class ViewHolder {
    TextView tvitemcode;
    TextView tvItemDesc;
    TextView tvPalletQty;
    EditText etvLocation;
    EditText barcode;
    TextView tvProgress;
    TextView textView;
}

2. 修改getView方法,复用ConvertView

@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    ProductionLineModel model = getItem(position);

    // 复用视图,避免重复inflate
    if (convertView == null) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        convertView = inflater.inflate(mResource, parent, false);
        holder = new ViewHolder();
        // 初始化所有视图引用
        holder.tvitemcode = convertView.findViewById(R.id.textView37);
        holder.tvItemDesc = convertView.findViewById(R.id.textView38);
        holder.tvPalletQty = convertView.findViewById(R.id.textView39);
        holder.etvLocation = convertView.findViewById(R.id.PROD_location_etv);
        holder.barcode = convertView.findViewById(R.id.PROD_barcode);
        holder.tvProgress = convertView.findViewById(R.id.Progress_tv);
        holder.textView = convertView.findViewById(R.id.textView40);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    // 填充基础数据
    holder.tvitemcode.setText(model.getItemcode());
    holder.tvItemDesc.setText(model.getItemdescription());
    holder.tvPalletQty.setText(model.getPalletqty());

    if (Objects.equals(status, "GECLAIMED")) {
        holder.barcode.setVisibility(View.VISIBLE);
        holder.tvProgress.setVisibility(View.GONE);
        // 从Model读取保存的输入内容
        holder.etvLocation.setText(model.getLocation());
        holder.barcode.setText(model.getBarcodeInput());

        // 输入监听:同步内容到Model,优化焦点处理
        holder.barcode.setOnEditorActionListener((v, actionId, event) -> {
            boolean isEnterEvent = event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN;
            if (actionId == EditorInfo.IME_ACTION_DONE || isEnterEvent) {
                String newScan = holder.barcode.getText().toString();
                model.setBarcodeInput(newScan); // 同步输入内容到Model

                if (!newScan.isEmpty()) {
                    if (Objects.equals(model.getPalletcode(), newScan)) {
                        if (dataBaseHelper.UpdateProdPallet(model.getPalletcode(), model.getOrderNummer())) {
                            Toast.makeText(mContext, "Pallet geaccepteerd", Toast.LENGTH_SHORT).show();
                            Log.d("DEBUG", "Pallet accepted");
                        } else {
                            Toast.makeText(mContext, "Pallet NIET geaccepteerd", Toast.LENGTH_SHORT).show();
                            Log.e("DEBUG", "Pallet NOT accepted due: Database");
                        }
                    } else {
                        Toast.makeText(mContext, "Pallet NIET geaccepteerd", Toast.LENGTH_SHORT).show();
                        Log.e("DEBUG", "Pallet NOT accepted due: Codes not equal");
                    }
                } else {
                    Toast.makeText(mContext, "Scan eerst een barcode", Toast.LENGTH_SHORT).show();
                    Log.e("DEBUG", "Pallet NOT accepted due: Nothing inserted");
                }

                // 隐藏键盘并清除焦点,避免焦点跳变
                InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                v.clearFocus();
                return true;
            }
            return false;
        });
    } else {
        holder.barcode.setVisibility(View.INVISIBLE);
        holder.tvProgress.setVisibility(View.VISIBLE);
        // 从Model读取保存的输入内容和状态
        holder.etvLocation.setText(model.getLocationInput());
        if (model.isPalletUpdated()) {
            holder.tvProgress.setText("Scan uw locatie");
            holder.textView.setText("Locatie");
        } else {
            holder.tvProgress.setText("Scan uw pallet");
            holder.textView.setText("Barcode");
        }

        holder.etvLocation.setOnEditorActionListener((v, actionId, event) -> {
            boolean isEnterEvent = event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN;
            if (actionId == EditorInfo.IME_ACTION_DONE || isEnterEvent) {
                String newScan = holder.etvLocation.getText().toString();
                model.setLocationInput(newScan); // 同步输入内容到Model

                if (!newScan.isEmpty()) {
                    if (Objects.equals(model.getPalletcode(), newScan)) {
                        if (!model.isPalletUpdated()) {
                            if (dataBaseHelper.UpdateProdPallet(model.getPalletcode(), model.getOrderNummer())) {
                                Toast.makeText(mContext, "Pallet geaccepteerd", Toast.LENGTH_SHORT).show();
                                model.setPalletUpdated(true); // 更新Model状态
                                holder.tvProgress.setText("Scan uw locatie");
                                holder.textView.setText("Locatie");
                            } else {
                                Toast.makeText(mContext, "Pallet NIET geaccepteerd", Toast.LENGTH_SHORT).show();
                            }
                        } else {
                            if (dataBaseHelper.UpdateProdPallet(model.getPalletcode(), model.getOrderNummer())) {
                                Toast.makeText(mContext, "Locatie verstuurd", Toast.LENGTH_SHORT).show();
                                model.setPalletUpdated(false); // 更新Model状态
                                holder.tvProgress.setText("Scan uw pallet");
                                holder.textView.setText("Barcode");
                            } else {
                                Toast.makeText(mContext, "Pallet NIET geaccepteerd", Toast.LENGTH_SHORT).show();
                            }
                        }
                    } else {
                        Toast.makeText(mContext, "Pallet NIET geaccepteerd", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(mContext, "Scan eerst een barcode", Toast.LENGTH_SHORT).show();
                }

                // 隐藏键盘并清除焦点
                InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                v.clearFocus();
                return true;
            }
            return false;
        });
    }
    return convertView;
}

3. 更新ProductionLineModel类

新增存储输入内容和状态的字段,确保数据持久化:

public class ProductionLineModel {
    // 原有字段...
    private String barcodeInput;
    private String locationInput;
    private boolean isPalletUpdated;

    // 新增getter和setter
    public String getBarcodeInput() {
        return barcodeInput;
    }

    public void setBarcodeInput(String barcodeInput) {
        this.barcodeInput = barcodeInput;
    }

    public String getLocationInput() {
        return locationInput;
    }

    public void setLocationInput(String locationInput) {
        this.locationInput = locationInput;
    }

    public boolean isPalletUpdated() {
        return isPalletUpdated;
    }

    public void setPalletUpdated(boolean palletUpdated) {
        isPalletUpdated = palletUpdated;
    }

    // 原有构造方法...
}

额外优化建议

  • 给ListView添加焦点管理属性,避免Item布局抢焦点:
<ListView
    android:id="@+id/Lines_lv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="beforeDescendants"/>
  • 确保硬件扫描器的输入不会触发额外焦点请求,EditText需保留android:focusable="true"和android:focusableInTouchMode="true"属性,但不要在代码中强制调用requestFocus()。

内容的提问来源于stack exchange,提问作者Joossieπ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 21:45:31