You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVVM模式下如何动态Inflate View?DataBinding新手求助

嘿,刚上手DataBinding和MVVM的话,这种动态增删视图的需求确实得换个思路——不能像传统写法那样直接在Activity里硬怼View操作了。我来给你拆解下MVVM模式下的标准实现方式,保证符合数据驱动UI的核心思想~

MVVM模式下动态增删视图实现方案

核心思路是用数据驱动视图:把动态视图的状态、增删逻辑全部放到ViewModel里,通过Observable集合管理数据,再让DataBinding自动完成视图的渲染和更新,完全避免在Activity/Fragment里直接操作View。

1. 定义单个动态视图的数据模型

每个要添加的双TextView视图,对应一个数据类来存储它的展示内容:

data class DynamicItem(
    val firstText: String,
    val secondText: String
)

2. 编写ViewModel管理数据与操作

ViewModel里维护一个Observable集合(DataBinding能监听它的变化),同时提供添加、删除的方法:

class MainViewModel : ViewModel() {
    // ObservableArrayList会自动通知DataBinding更新UI
    val itemList = ObservableArrayList<DynamicItem>()

    // 添加按钮的点击逻辑:往集合里加新数据
    fun onAddItemClick() {
        // 这里可以根据业务生成真实数据,我这里用序号模拟
        val newItem = DynamicItem(
            "第一栏文本${itemList.size + 1}",
            "第二栏文本${itemList.size + 1}"
        )
        itemList.add(newItem)
    }

    // 删除指定项的逻辑:从集合里移除对应数据
    fun onDeleteItemClick(item: DynamicItem) {
        itemList.remove(item)
    }
}

3. 编写动态视图的子布局

创建item_dynamic.xml,这是你要动态加载的双TextView+删除按钮布局,同时绑定数据和ViewModel的删除方法:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <!-- 当前项的数据 -->
        <variable
            name="item"
            type="com.yourpackage.DynamicItem" />
        <!-- 全局ViewModel -->
        <variable
            name="viewModel"
            type="com.yourpackage.MainViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp"
        android:gravity="center_vertical">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@{item.firstText}" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@{item.secondText}" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="删除"
            android:onClick="@{() -> viewModel.onDeleteItemClick(item)}" />
    </LinearLayout>
</layout>

4. 编写主布局与RecyclerView绑定

MVVM里动态列表首选RecyclerView(性能和可维护性都更好),主布局activity_main.xml里添加添加按钮和RecyclerView,绑定ViewModel:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewModel"
            type="com.yourpackage.MainViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="添加视图"
            android:onClick="@{() -> viewModel.onAddItemClick()}" />

        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:itemList="@{viewModel.itemList}"
            app:viewModel="@{viewModel}"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
    </LinearLayout>
</layout>

5. 编写DataBinding版RecyclerView Adapter

这个适配器负责把数据和子布局绑定:

class DynamicItemAdapter : RecyclerView.Adapter<DynamicItemAdapter.ViewHolder>() {
    private var items: List<DynamicItem> = emptyList()
    lateinit var viewModel: MainViewModel

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = ItemDynamicBinding.inflate(inflater, parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = items[position]
        holder.binding.item = item
        holder.binding.viewModel = viewModel
        holder.binding.executePendingBindings() // 立即完成绑定,避免延迟
    }

    override fun getItemCount(): Int = items.size

    // 更新数据的方法,ViewModel的集合变化时调用
    fun submitList(newItems: List<DynamicItem>) {
        items = newItems
        notifyDataSetChanged()
    }

    class ViewHolder(val binding: ItemDynamicBinding) : RecyclerView.ViewHolder(binding.root)
}

6. 添加BindingAdapter连接RecyclerView与数据

写一个BindingAdapter,让RecyclerView能自动接收ViewModel的集合数据:

object RecyclerViewBindingAdapters {
    @BindingAdapter("itemList", "viewModel")
    @JvmStatic
    fun setupRecyclerView(
        recyclerView: RecyclerView,
        itemList: List<DynamicItem>?,
        viewModel: MainViewModel?
    ) {
        // 初始化适配器(如果还没有的话)
        val adapter = recyclerView.adapter as? DynamicItemAdapter ?: run {
            DynamicItemAdapter().also { recyclerView.adapter = it }
        }
        // 绑定ViewModel和数据
        viewModel?.let { adapter.viewModel = it }
        itemList?.let { adapter.submitList(it) }
    }
}

7. 在Activity中完成最终绑定

最后在Activity里初始化DataBinding和ViewModel,把它们关联起来:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val viewModel = ViewModelProvider(this)[MainViewModel::class.java]
        binding.viewModel = viewModel
        binding.lifecycleOwner = this // 让DataBinding感知生命周期,自动更新UI
    }
}

最后要注意的点

别忘了在app模块的build.gradle里开启DataBinding:

android {
    ...
    buildFeatures {
        dataBinding true
    }
}

这样一来,点击添加按钮时,ViewModel会往集合里加数据,DataBinding自动通知RecyclerView新增视图;点击删除按钮时,ViewModel移除对应数据,视图也会自动消失——完全符合MVVM数据驱动UI的理念,没有任何直接操作View的代码~

内容的提问来源于stack exchange,提问作者Codershree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:16:06