如何修复Android中adapter.notifyDataSetChanged()无法生效的问题
解决
adapter.notifyDataSetChanged()无法刷新ListView的问题 咱们先拆解代码里的几个核心问题,这些问题直接导致刷新方法失效:
1. 适配器与数据源不匹配且未正确关联
你的代码里存在两个完全独立的数据源:
showEmployee()里用的是ArrayList<HashMap<String,String>>作为SimpleAdapter的数据源cariData()里操作的是成员变量List<DataModel> listData
同时,成员变量adapter从未被正确赋值——showEmployee()里创建的是局部ListAdapter,和成员变量adapter完全没关系,所以调用adapter.notifyDataSetChanged()时,要么是null,要么不是ListView正在使用的适配器。
2. 刷新时机错误
在cariData()里,你先调用了adapter.notifyDataSetChanged()再往listData里添加数据,这时候数据源还是空的,刷新自然不会有效果。
具体修复步骤
第一步:统一数据源与适配器
首先,咱们把所有数据源统一为List<DataModel>,并自定义一个适配DataModel的适配器(替代原来的SimpleAdapter):
// 自定义适配器类,可放在SemuaData类内部或单独文件中 private class DataAdapter extends BaseAdapter { private Context context; private List<DataModel> dataList; public DataAdapter(Context context, List<DataModel> dataList) { this.context = context; this.dataList = dataList; } @Override public int getCount() { return dataList.size(); } @Override public Object getItem(int position) { return dataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false); } DataModel data = dataList.get(position); // 绑定数据到布局控件 TextView tvId = convertView.findViewById(R.id.id); TextView tvNama = convertView.findViewById(R.id.nama); tvId.setText(data.getId()); tvNama.setText(data.getNama()); return convertView; } }
第二步:修改showEmployee()方法,统一数据源与适配器
把原来的HashMap数据源替换成listData,并初始化成员变量adapter:
private void showEmployee(){ JSONObject jsonObject = null; listData.clear(); // 先清空旧数据 try { jsonObject = new JSONObject(JSON_STRING); JSONArray result = jsonObject.getJSONArray(Config.TAG_JSON_ARRAY); for(int i = 0; i<result.length(); i++){ JSONObject jo = result.getJSONObject(i); DataModel data = new DataModel(); data.setId(jo.getString(Config.TAG_ID)); data.setNama(jo.getString(Config.TAG_NAMA)); data.setUmur(jo.getString(Config.TAG_UMUR)); data.setAlamat(jo.getString(Config.TAG_ALAMAT)); listData.add(data); } } catch (JSONException e) { e.printStackTrace(); } // 初始化成员变量adapter,绑定到ListView adapter = new DataAdapter(this, listData); list_view.setAdapter(adapter); }
第三步:修正cariData()方法的逻辑顺序
先更新数据源,再调用刷新方法,同时确保操作的是同一个listData和adapter:
private void cariData(final String keyword) { StringRequest strReq = new StringRequest(Request.Method.POST, Config.url_cari, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.e("DATA RESPONSE SEARCH : ", response.toString()); try { JSONObject jObj = new JSONObject(response); int value = jObj.getInt(TAG_VALUE); if (value == 1) { listData.clear(); // 清空旧数据 String getObject = jObj.getString(TAG_RESULTS); JSONArray jsonArray = new JSONArray(getObject); for (int i = 0; i < jsonArray.length(); i++) { JSONObject obj = jsonArray.getJSONObject(i); DataModel data = new DataModel(); data.setId(obj.getString(TAG_ID)); data.setNama(obj.getString(TAG_NAMA)); data.setUmur(obj.getString(TAG_UMUR)); data.setAlamat(obj.getString(TAG_ALAMAT)); listData.add(data); } // 数据源更新完成后再刷新 adapter.notifyDataSetChanged(); } else { Toast.makeText(getApplicationContext(), jObj.getString(TAG_MESSAGE), Toast.LENGTH_SHORT).show(); } } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e(TAG, "Error: " + error.getMessage()); Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_SHORT).show(); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put("keyword", keyword); return params; } }; AppController.getInstance().addToRequestQueue(strReq, tag_json_obj); }
第四步:修正成员变量声明
确保成员变量adapter的类型是咱们自定义的DataAdapter:
// 替换原来的Adapter adapter; private DataAdapter adapter;
额外优化建议
- 可以在
onQueryTextChange()里实现实时搜索逻辑,提升用户体验:
@Override public boolean onQueryTextChange(String newText) { if (TextUtils.isEmpty(newText)) { // 输入为空时重新加载全部数据 getJSON(); } else { cariData(newText); } return true; }
- 注意Volley的
onResponse已经在主线程执行,所以直接调用notifyDataSetChanged()是安全的,其他异步操作要确保在主线程更新UI。
内容的提问来源于stack exchange,提问作者Rijal Khalik
相关产品推荐
相关产品推荐

