Android Studio中如何在onBindViewHolder中应用条件并调整RecyclerView条目数
解决RecyclerView按距离过滤工人数据的正确实现
原代码核心问题
onBindViewHolder中使用do-while循环遍历整个数据集是错误的:该方法是每个item绑定视图时调用,每次调用都遍历会导致重复计算、索引混乱,甚至引发崩溃。- 绑定过程中直接修改数据源(
remove元素)并调用notifyItemRemoved,会破坏RecyclerView的回收机制,导致视图展示异常。 count变量维护逻辑混乱,无法准确反映实际需要展示的item数量。- 直接引用静态类的坐标变量,耦合性过高,不利于代码维护。
正确实现方案
1. 封装Haversine距离计算工具方法
把距离计算逻辑抽成独立方法,提升复用性和代码可读性:
public class DistanceCalculator { private static final double EARTH_RADIUS_KM = 6371; public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { double dLat = Math.toRadians(lat2 - lat1); double dLon = Math.toRadians(lon2 - lon1); lat1 = Math.toRadians(lat1); lat2 = Math.toRadians(lat2); double a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2); double c = 2 * Math.asin(Math.sqrt(a)); return EARTH_RADIUS_KM * c; } }
2. 修正后的RecyclerView Adapter
Adapter只负责展示过滤后的数据,过滤逻辑提前完成:
public class WorkerAdapter extends RecyclerView.Adapter<WorkerAdapter.WorkerViewHolder> { private Context context; private ArrayList<user_data> filteredWorkerList; // 构造方法:传入上下文、原始工人列表和客户端坐标,直接完成数据过滤 public WorkerAdapter(Context context, ArrayList<user_data> originalWorkerList, double clientLat, double clientLon) { this.context = context; this.filteredWorkerList = filterWorkersByDistance(originalWorkerList, clientLat, clientLon); } // 过滤符合距离条件的工人 private ArrayList<user_data> filterWorkersByDistance(ArrayList<user_data> originalList, double clientLat, double clientLon) { ArrayList<user_data> filteredList = new ArrayList<>(); for (user_data worker : originalList) { double workerLat = worker.getWorker_lattitude(); double workerLon = worker.getWorker_longitude(); double workingRadius = worker.getWork_Km(); // 计算工人与客户端的距离 double distance = DistanceCalculator.calculateDistance(workerLat, workerLon, clientLat, clientLon); // 距离小于等于工作半径则保留 if (distance <= workingRadius) { filteredList.add(worker); } } return filteredList; } @NonNull @Override public WorkerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.single_row, parent, false); return new WorkerViewHolder(view); } @Override public void onBindViewHolder(@NonNull WorkerViewHolder holder, int position) { // 直接绑定过滤后的数据,无需额外判断 user_data worker = filteredWorkerList.get(position); holder.w_name.setText(worker.getWorker_Name()); holder.w_desc.setText(worker.getWorker_description()); } @Override public int getItemCount() { // 直接返回过滤后列表的大小,无需维护额外count变量 return filteredWorkerList.size(); } public static class WorkerViewHolder extends RecyclerView.ViewHolder { TextView w_name, w_desc; public WorkerViewHolder(@NonNull View itemView) { super(itemView); w_name = itemView.findViewById(R.id.worker_name); w_desc = itemView.findViewById(R.id.worker_desc); } } // 可选:客户端坐标更新时,重新过滤数据并刷新列表 public void updateClientLocation(double newClientLat, double newClientLon, ArrayList<user_data> originalWorkerList) { this.filteredWorkerList = filterWorkersByDistance(originalWorkerList, newClientLat, newClientLon); notifyDataSetChanged(); } }
3. 使用示例
在Activity/Fragment中获取客户端坐标和Firestore工人数据后,初始化Adapter:
// 假设已获取客户端经纬度clientLat、clientLon,以及Firestore返回的workerList WorkerAdapter adapter = new WorkerAdapter(this, workerList, clientLat, clientLon); recyclerView.setAdapter(adapter);
内容的提问来源于stack exchange,提问作者dinesh dine
相关产品推荐
相关产品推荐

