如何根据州AutoCompleteTextView的选择填充城市AutoCompleteTextView?
实现州选择联动城市AutoCompleteTextView的解决方案
看起来你已经完成了基础的州和城市数据加载,只需要补上州选择后联动更新城市下拉选项的逻辑就可以了,同时还能保留用户手动输入城市的功能。下面是修改后的完整代码和关键说明:
关键修改点
- 把
edtxt_state的OnItemSelectedListener替换为OnItemClickListener(AutoCompleteTextView更适合用这个监听,避免下拉展开时的误触发) - 在州选中的回调里,匹配对应城市列表并更新城市AutoCompleteTextView的适配器
- 确保城市输入框既可以自动加载联动选项,也支持用户手动输入
修改后的MainActivity.java
public class MainActivity extends AppCompatActivity { EditText edtxt_name_address, edtxt_email_address, edtxt_mobile_address, edtxt_alt_mob_address, edtxt_pincode, edtxt_addline1, edtxt_addline2; Button buttonSaveAddress; AutoCompleteTextView edtxt_city, edtxt_state; private static final String KEY_STATE = "state"; private static final String KEY_CITIES = "cities"; private String cities_url = "http://api.androiddeft.com/cities/cities_array.json"; final List<State> statesList = new ArrayList<>(); final List<String> states = new ArrayList<>(); // 声明城市适配器,方便后续更新 private ArrayAdapter<String> cityAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edtxt_city = findViewById(R.id.edtxt_city); edtxt_state = findViewById(R.id.edtxt_state); loadStateCityDetails(); // 初始化州的适配器 ArrayAdapter<String> stateAdapter = new ArrayAdapter<>(this, android.R.layout.select_dialog_item, states); edtxt_state.setThreshold(1); edtxt_state.setAdapter(stateAdapter); // 州选择的点击监听(替换原来的OnItemSelectedListener) edtxt_state.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // 获取选中的州名称 String selectedState = states.get(position); // 找到对应州的城市列表 List<String> matchedCities = new ArrayList<>(); for (State state : statesList) { if (state.getStateName().equals(selectedState)) { matchedCities = state.getCities(); break; } } // 更新城市AutoCompleteTextView的适配器 cityAdapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.select_dialog_item, matchedCities); edtxt_city.setThreshold(1); edtxt_city.setAdapter(cityAdapter); // 可选:自动清空之前的城市输入,避免混淆 edtxt_city.setText(""); } }); buttonSaveAddress = findViewById(R.id.buttonSaveAddress); buttonSaveAddress.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { saveAddress(); } }); } private void loadStateCityDetails() { JsonArrayRequest jsArrayRequest = new JsonArrayRequest(Request.Method.GET, cities_url, null, new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray responseArray) { try { for (int i = 0; i < responseArray.length(); i++) { JSONObject response = responseArray.getJSONObject(i); String state = response.getString(KEY_STATE); JSONArray cities = response.getJSONArray(KEY_CITIES); List<String> citiesList = new ArrayList<>(); for (int j = 0; j < cities.length(); j++) { citiesList.add(cities.getString(j)); } statesList.add(new State(state, citiesList)); states.add(state); } // 数据加载完成后,刷新州的适配器(如果初始化时数据还没加载完) ((ArrayAdapter)edtxt_state.getAdapter()).notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "数据解析失败", Toast.LENGTH_SHORT).show(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(getApplicationContext(), "加载数据失败:" + error.getMessage(), Toast.LENGTH_SHORT).show(); } }); MySingleton.getInstance(this).addToRequestQueue(jsArrayRequest); } private void saveAddress() { String city = edtxt_city.getText().toString().trim(); String state = edtxt_state.getText().toString().trim(); if (TextUtils.isEmpty(city)) { edtxt_city.setError("Please enter your City"); edtxt_city.requestFocus(); return; } if (TextUtils.isEmpty(state)) { edtxt_state.setError("Please enter your State"); edtxt_state.requestFocus(); return; } Intent profile_next = new Intent(MainActivity.this, ProfileNextActivity.class); startActivity(profile_next); } }
State.java(无需修改,保持原样)
public class State { private String stateName; private List<String> cities; public State(String stateName, List<String> cities) { this.stateName = stateName; this.cities = cities; } public String getStateName() { return stateName; } public List<String> getCities() { return cities; } }
额外说明
为什么用OnItemClickListener?
AutoCompleteTextView的OnItemSelectedListener会在下拉列表展开时自动选中第一项(即使用户没点击),导致不必要的联动。而OnItemClickListener只有当用户真正点击选中某一个州时才触发,逻辑更准确。保留手动输入能力
代码中没有限制城市输入框的编辑权限,用户既可以选择自动加载的城市选项,也可以手动输入自定义的城市名称,完全符合你提到的电商APP类似需求。数据加载后的适配器刷新
因为Volley请求是异步的,初始化州适配器时可能数据还没加载完成,所以在loadStateCityDetails的onResponse末尾加上notifyDataSetChanged(),确保数据加载完成后州的下拉选项能正常显示。
内容的提问来源于stack exchange,提问作者Abhishek Kumar
相关产品推荐
相关产品推荐

