AutocompleteTextView调用dismissDropDown()无效问题求助
问题
我用AutocompleteTextView实现远程搜索功能,文本内容变化时发起HTTP请求从远程数据库拉取数据。目前遇到两个矛盾的问题:
- 点击下拉列表选项时,TextWatcher会把填充文本的操作检测为文本变化,导致下拉框始终无法关闭——哪怕在
setOnItemClickListener里调用dismissDropDown()也没用 - 如果不手动调用
showDropdown(),点击选项后下拉框能正常关闭,但搜索结果显示异常,比如明明有8条结果,只显示2条甚至完全不显示
问题根源
- TextWatcher被重复触发:点击选项时,AutocompleteTextView会自动填充选中的文本,这会触发TextWatcher的
onTextChanged方法,重新发起请求并调用showDropDown(),把刚关掉的下拉框又弹出来 - 重复初始化组件:每次文本变化都重新创建Adapter、设置
setOnItemClickListener,不仅浪费资源,还会导致组件状态混乱,出现结果显示异常 - 手动干扰默认逻辑:强制调用
showDropDown()会打乱AutocompleteTextView的默认显示机制,导致结果展示异常
解决方案
- 临时禁用TextWatcher:点击选项填充文本时,先移除TextWatcher,避免触发不必要的请求,填充完成后再重新添加
- 提前初始化核心组件:把Adapter初始化和
setOnItemClickListener移到TextWatcher外面,仅在请求成功后更新Adapter的数据,而非每次都重新创建 - 移除手动
showDropDown()调用:让AutocompleteTextView自行管理下拉框的显示,只在数据更新时通知Adapter刷新
修改后的Java代码
// 提前声明全局变量 private ArrayAdapter<Deposito> depositoAdapter; private TextWatcher depositoTextWatcher; private AutoCompleteTextView autocompleteDeposito; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout_id); // 替换为你的布局ID autocompleteDeposito = findViewById(R.id.autocompleteDeposito); // 初始化空Adapter,仅执行一次 depositoAdapter = new ArrayAdapter<>( RegistroActivity.this, android.R.layout.simple_dropdown_item_1line, new ArrayList<>() ); autocompleteDeposito.setThreshold(2); autocompleteDeposito.setAdapter(depositoAdapter); // 设置Item点击监听,仅初始化一次 autocompleteDeposito.setOnItemClickListener((parent, view, position, id) -> { Deposito depositoSeleccionado = (Deposito) parent.getItemAtPosition(position); depositoSeleccionadoId = depositoSeleccionado.getId(); // 临时移除TextWatcher,避免填充文本触发请求 autocompleteDeposito.removeTextChangedListener(depositoTextWatcher); // 手动设置文本(确保选中内容正确填充) autocompleteDeposito.setText(depositoSeleccionado.getNombre()); // 重新添加TextWatcher autocompleteDeposito.addTextChangedListener(depositoTextWatcher); }); // 初始化TextWatcher depositoTextWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { String nombreDeposito = charSequence.toString().trim(); // 文本长度小于阈值时清空结果 if (nombreDeposito.length() < 2) { depositoAdapter.clear(); return; } String url = "http://MY_SERVER_IP/buscarDeposito.php"; StringRequest stringRequest = new StringRequest(Request.Method.POST, url, response -> { try { JSONObject jsonObject = new JSONObject(response); boolean success = jsonObject.getBoolean("success"); if (success) { JSONArray data = jsonObject.getJSONArray("data"); ArrayList<Deposito> depositoList = new ArrayList<>(); for (int j = 0; j < data.length(); j++) { JSONObject item = data.getJSONObject(j); String idDeposito = item.getString("id"); String nombre = item.getString("nombre"); depositoList.add(new Deposito(nombre, idDeposito)); } // 更新Adapter数据,而非重建Adapter depositoAdapter.clear(); depositoAdapter.addAll(depositoList); depositoAdapter.notifyDataSetChanged(); } else { depositoAdapter.clear(); Toast.makeText(RegistroActivity.this, "未找到匹配的仓库", Toast.LENGTH_SHORT).show(); } } catch (JSONException e) { e.printStackTrace(); Toast.makeText(RegistroActivity.this, "处理响应出错", Toast.LENGTH_LONG).show(); } }, error -> { depositoAdapter.clear(); Toast.makeText(RegistroActivity.this, "请求失败", Toast.LENGTH_SHORT).show(); }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<>(); params.put("nombre_deposito", nombreDeposito); return params; } }; RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext()); requestQueue.add(stringRequest); } @Override public void afterTextChanged(Editable editable) {} }; // 添加TextWatcher到控件 autocompleteDeposito.addTextChangedListener(depositoTextWatcher); }
XML代码(无需修改)
<AutoCompleteTextView android:id="@+id/autocompleteDeposito" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="44dp" android:layout_marginTop="180dp" android:layout_marginEnd="44dp" android:hint="@string/deposito_autocomplete" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/toolbar" />
内容的提问来源于stack exchange,提问作者pmpato
相关产品推荐
相关产品推荐

