如何在Adapter中通过Dialog更新数据后刷新RecyclerView
问题描述
我的应用需要通过弹窗(Dialog)更新和删除RecyclerView中的条目,弹窗在点击弹出菜单(PopupMenu)后打开。我已经在Adapter类的onBindViewHolder方法中实现了弹窗功能,且服务器端的数据更新与删除操作已成功完成,请问如何在此操作后刷新RecyclerView?
Adapter.java 核心代码
holder.cBtnMore.setOnClickListener(v -> { PopupMenu popupMenu = new PopupMenu(v.getContext(), holder.cBtnMore); popupMenu.getMenuInflater().inflate(R.menu.more_menu, popupMenu.getMenu()); popupMenu.setOnMenuItemClickListener(menuItem -> { if (menuItem.getItemId() == R.id.menu_update) { final Dialog dialog = new Dialog(v.getContext()); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.dialog_update); dialog.getWindow().setLayout(Cons.widthScreen, Cons.heightScreen); // 控件声明与文本设置... btnUpdate.setOnClickListener(unused -> { updateBarang( v.getContext(), id, etNama.getText().toString(), etAlamat.getText().toString(), etNoPenjual.getText().toString(), etKodeBarang.getText().toString(), etJumlahPenjualan.getText().toString(), etHargaSatuan.getText().toString(), etDiskon.getText().toString(), etTotalHarga.getText().toString() ); }); btnCancel.setOnClickListener(unused -> { dialog.dismiss(); }); dialog.show(); } else if (menuItem.getItemId() == R.id.menu_delete) { Toast.makeText(v.getContext(), "Delete", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(v.getContext(), "Error", Toast.LENGTH_SHORT).show(); } return true; }); popupMenu.show(); });
MainActivity.java 核心代码
public class MainActivity extends AppCompatActivity { FloatingActionButton fabAdd; RecyclerView rvBarang; ApiInterface apiInterface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); apiInterface = ApiConnection.Connection().create(ApiInterface.class); // ...其他初始化代码 rvBarang.setLayoutManager(new LinearLayoutManager(this)); } @Override protected void onResume() { Call<List<Barang>> tampilBarang = apiInterface.listBarang(); tampilBarang.enqueue(new Callback<List<Barang>>() { @Override public void onResponse(Call<List<Barang>> call, Response<List<Barang>> response) { ArrayList<Barang> barangArrayList = (ArrayList<Barang>) response.body(); BarangAdapter barangAdapter = new BarangAdapter(barangArrayList); rvBarang.setAdapter(barangAdapter); } @Override public void onFailure(Call<List<Barang>> call, Throwable t) { // TODO 处理请求失败 } }); super.onResume(); } }
解决方案
方法一:更新本地数据集+局部刷新(推荐)
这种方式无需重新请求服务器,效率更高,是RecyclerView刷新的最佳实践。
1. 改造Adapter,添加数据操作方法
在BarangAdapter中保留数据集引用,并实现更新、删除单条数据的方法:
public class BarangAdapter extends RecyclerView.Adapter<BarangAdapter.ViewHolder> { private ArrayList<Barang> mBarangList; public BarangAdapter(ArrayList<Barang> barangList) { this.mBarangList = barangList; } // 更新指定位置的条目 public void updateItem(int position, Barang updatedBarang) { mBarangList.set(position, updatedBarang); notifyItemChanged(position); // 仅刷新目标条目,性能更优 } // 删除指定位置的条目 public void removeItem(int position) { mBarangList.remove(position); notifyItemRemoved(position); // 通知后续条目位置更新 notifyItemRangeChanged(position, mBarangList.size() - position); } // 获取数据集(供外部调用) public ArrayList<Barang> getBarangList() { return mBarangList; } // 原有ViewHolder、onCreateViewHolder等代码... }
2. 改造MainActivity,全局持有Adapter和数据集
将Adapter和数据集设为全局变量,方便后续操作:
public class MainActivity extends AppCompatActivity { FloatingActionButton fabAdd; RecyclerView rvBarang; ApiInterface apiInterface; private BarangAdapter barangAdapter; private ArrayList<Barang> barangArrayList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); apiInterface = ApiConnection.Connection().create(ApiInterface.class); rvBarang.setLayoutManager(new LinearLayoutManager(this)); } @Override protected void onResume() { super.onResume(); fetchBarangData(); } // 封装数据请求方法 public void fetchBarangData() { Call<List<Barang>> tampilBarang = apiInterface.listBarang(); tampilBarang.enqueue(new Callback<List<Barang>>() { @Override public void onResponse(Call<List<Barang>> call, Response<List<Barang>> response) { barangArrayList = (ArrayList<Barang>) response.body(); barangAdapter = new BarangAdapter(barangArrayList); rvBarang.setAdapter(barangAdapter); } @Override public void onFailure(Call<List<Barang>> call, Throwable t) { // 处理请求失败逻辑,比如弹出Toast } }); } // 提供外部访问Adapter的方法 public BarangAdapter getBarangAdapter() { return barangAdapter; } public ArrayList<Barang> getBarangArrayList() { return barangArrayList; } }
3. 更新操作:服务器成功后同步本地数据
在updateBarang方法的网络请求成功回调中,更新本地数据集并通知Adapter:
private void updateBarang(Context context, String id, String nama, String alamat, String noPenjual, String kodeBarang, String jumlahPenjualan, String hargaSatuan, String diskon, String totalHarga) { apiInterface.updateBarang(id, nama, alamat, noPenjual, kodeBarang, jumlahPenjualan, hargaSatuan, diskon, totalHarga) .enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { MainActivity activity = (MainActivity) context; // 找到目标条目的位置 int targetPosition = -1; for (int i = 0; i < activity.getBarangArrayList().size(); i++) { if (activity.getBarangArrayList().get(i).getId().equals(id)) { targetPosition = i; break; } } if (targetPosition != -1) { // 创建更新后的Barang对象 Barang updatedBarang = new Barang(); updatedBarang.setId(id); updatedBarang.setNama(nama); updatedBarang.setAlamat(alamat); updatedBarang.setNoPenjual(noPenjual); updatedBarang.setKodeBarang(kodeBarang); updatedBarang.setJumlahPenjualan(jumlahPenjualan); updatedBarang.setHargaSatuan(hargaSatuan); updatedBarang.setDiskon(diskon); updatedBarang.setTotalHarga(totalHarga); // 通知Adapter更新条目 activity.getBarangAdapter().updateItem(targetPosition, updatedBarang); } // 关闭弹窗 dialog.dismiss(); Toast.makeText(context, "更新成功", Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Toast.makeText(context, "更新失败", Toast.LENGTH_SHORT).show(); } }); }
4. 删除操作:服务器成功后移除本地条目
在PopupMenu的删除分支中,获取条目位置并发起删除请求,成功后同步本地数据:
else if (menuItem.getItemId() == R.id.menu_delete) { int position = holder.getAdapterPosition(); // 检查位置有效性,避免条目已被回收 if (position != RecyclerView.NO_POSITION) { Barang targetBarang = barangAdapter.getBarangList().get(position); String id = targetBarang.getId(); // 发起删除请求 apiInterface.deleteBarang(id).enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { MainActivity activity = (MainActivity) v.getContext(); activity.getBarangAdapter().removeItem(position); Toast.makeText(v.getContext(), "删除成功", Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Toast.makeText(v.getContext(), "删除失败", Toast.LENGTH_SHORT).show(); } }); } }
方法二:重新请求服务器数据(简单但效率低)
如果不想维护本地数据集的同步,可以在服务器操作成功后,重新调用数据请求方法刷新整个列表:
在更新/删除的成功回调中,调用MainActivity的fetchBarangData方法:
// 更新成功回调示例 if (response.isSuccessful()) { dialog.dismiss(); ((MainActivity)context).fetchBarangData(); Toast.makeText(context, "更新成功", Toast.LENGTH_SHORT).show(); }
注意事项
- 优先使用方法一的局部刷新,避免
notifyDataSetChanged()(会刷新整个列表,性能差)。 - 必须在主线程调用Adapter的通知方法(网络回调默认在子线程,若需要可通过
runOnUiThread切换)。 - 获取条目位置时,务必检查
position != RecyclerView.NO_POSITION,防止条目已被回收导致的异常。
内容的提问来源于stack exchange,提问作者Koh Endru
相关产品推荐
相关产品推荐

