如何基于LiveData变化高效更新绝对定位的用户视图?
实现绝对定位用户视图的高效增量更新
核心思路
当前方案每次更新都清空所有视图再重建,效率极低。我们需要维护用户视图的缓存映射,根据LiveData列表的变化(新增、删除、更新)只修改需要变更的视图,避免全量重建。
具体实现步骤
1. 调整ViewModel,直接暴露LiveData列表
修改UserViewModel.kt,把LiveData作为公开属性,方便DataBinding直接绑定:
class UserViewModel(private val repository: UserRepository) : ViewModel() { // 直接公开用户列表LiveData,替代原有的getUsers()方法 val users: LiveData<List<User>> = repository.getUsers() fun selectUser(id: String) { repository.selectUser(id) } }
2. 修改布局的BindingAdapter绑定目标
更新activity_main.xml,将users属性绑定到ViewModel的users LiveData,而非ViewModel本身:
<RelativeLayout android:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent" users="@{userVM.users}"> <!-- 绑定LiveData列表 --> </RelativeLayout>
3. 重写BindingAdapter实现增量更新
修改BindingAdapter.kt,维护用户ID与视图绑定对象的缓存,监听LiveData变化并处理三种场景:新增、删除、更新:
// 缓存用户ID对应的视图绑定对象,避免重复创建 private val userViewCache = mutableMapOf<String, ViewUserBinding>() @BindingAdapter("users") fun RelativeLayout.updateUsers(usersLiveData: LiveData<List<User>>) { // 移除旧的观察者,避免重复监听 usersLiveData.removeObservers(context as LifecycleOwner) usersLiveData.observe(context as LifecycleOwner) { newUsers -> val currentUserIds = userViewCache.keys.toSet() val newUserIds = newUsers.map { it.id }.toSet() // 1. 处理删除:移除已不存在的用户视图 currentUserIds.subtract(newUserIds).forEach { removedId -> userViewCache[removedId]?.let { binding -> this.removeView(binding.root) userViewCache.remove(removedId) } } // 2. 处理新增和更新:创建新视图或更新已有视图 newUsers.forEach { user -> val existingBinding = userViewCache[user.id] if (existingBinding == null) { // 新增用户:创建视图并绑定数据 val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val binding = DataBindingUtil.inflate<ViewUserBinding>( inflater, R.layout.view_user, this, false ) binding.user = user binding.userVM = ViewModelProvider(context as ViewModelStoreOwner)[UserViewModel::class.java] binding.lifecycleOwner = context as LifecycleOwner // 设置绝对定位布局参数 val layoutParams = RelativeLayout.LayoutParams(50, 50).apply { leftMargin = user.geo.x topMargin = user.geo.y } this.addView(binding.root, layoutParams) userViewCache[user.id] = binding } else { // 更新用户:仅当数据或位置变化时更新 if (existingBinding.user != user || existingBinding.root.layoutParams.leftMargin != user.geo.x || existingBinding.root.layoutParams.topMargin != user.geo.y) { existingBinding.user = user // 更新位置参数 (existingBinding.root.layoutParams as RelativeLayout.LayoutParams).apply { leftMargin = user.geo.x topMargin = user.geo.y } existingBinding.root.requestLayout() } } } } }
4. 确保MainActivity的LifecycleOwner设置正确
MainActivity.kt中已设置binding.lifecycleOwner = this,无需额外修改,确保LiveData的观察者能正确感知生命周期。
关键优化点
- 视图缓存:用
Map<String, ViewUserBinding>存储用户ID与视图的映射,避免重复创建视图 - 增量更新:仅处理新增、删除、数据/位置变化的用户,跳过无变化的视图
- LiveData监听:直接绑定LiveData并在Adapter中观察,确保数据变化时实时响应
内容的提问来源于stack exchange,提问作者Bilal Kazi
相关产品推荐
相关产品推荐

