
本文介绍一种简洁可靠的方式,将当前用户位置与学校位置的距离计算并展示在 recyclerview 的每个 school 列表项中,核心是通过向 adapter 传入 user 实例,并在 onbindviewholder 中调用 android 原生 location.distancebetween 进行高效距离计算。
本文介绍一种简洁可靠的方式,将当前用户位置与学校位置的距离计算并展示在 recyclerview 的每个 school 列表项中,核心是通过向 adapter 传入 user 实例,并在 onbindviewholder 中调用 android 原生 location.distancebetween 进行高效距离计算。
在开发基于地理位置的教育类 App(如附近学校列表)时,常需在每个 RecyclerView 列表项中显示“距您 X.X 公里”。由于 SchoolAdapter 默认只持有 List<school></school>,无法直接获取当前用户坐标,因此关键在于将用户上下文安全、解耦地注入 Adapter。
✅ 正确做法:将 User 实例作为依赖传入 Adapter
首先,在自定义 SchoolAdapter 中添加 User 字段,并在构造函数中接收:
class SchoolAdapter(
private val schools: List<school>,
private val currentUser: User // ? 关键:持有用户实例
) : RecyclerView.Adapter<schooladapter.viewholder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val school = schools[position]
holder.bind(school, currentUser)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tvName: TextView = itemView.findViewById(R.id.tv_school_name)
private val tvDistance: TextView = itemView.findViewById(R.id.tv_distance)
fun bind(school: School, user: User) {
tvName.text = school.name
// ✅ 使用 Android 原生 API 计算两点间球面距离(单位:米)
val distanceMeters = FloatArray(1)
Location.distanceBetween(
user.latitude, user.longitude,
school.latitude, school.longitude,
distanceMeters
)
// 格式化为“1.2 km”或“345 m”
val distanceStr = when {
distanceMeters[0] "${distanceMeters[0].toInt()} m"
else -> "${String.format("%.1f", distanceMeters[0] / 1000)} km"
}
tvDistance.text = distanceStr
}
}
}</schooladapter.viewholder></school>
⚠️ 注意事项与最佳实践
-
线程安全:
distanceBetween()是纯数学计算,无需主线程限制,但务必在onBindViewHolder(即主线程)中调用,避免跨线程 UI 更新。 -
空值防护:实际使用中建议对
user.latitude/longitude和school.latitude/longitude做非空与有效范围校验(如-90 ≤ lat ≤ 90,-180 ≤ lng ≤ 180),防止异常。 -
性能优化:距离计算开销极小(O(1)),无需额外缓存;若后续需支持排序(如按距离升序),可在数据层预计算并存入
School实体的临时字段(如distanceToUser: Double?),提升 RecyclerView 复用效率。 -
扩展性提示:如未来需支持多用户切换或定位更新,可将
currentUser改为LiveData<user></user>或使用DiffUtil配合submitList()重载实现响应式刷新。
通过该方案,Adapter 既保持职责单一(负责展示),又具备必要上下文,无需在 Fragment 中手动遍历 ViewHolder 或使用 findViewHolderForAdapterPosition() 等反模式操作——真正实现清晰、可测、可维护的地理距离展示逻辑。










