最近用MVVM,来总结一下

MVVM 概念梳理

一、MVVM 概念

MVVM(Model-View-ViewModel)是一种软件架构设计模式,最早由微软提出,特别适用于构建用户界面的应用程序。在MVVM模式中,界面被拆分为三个核心部分:Model、View 和 ViewModel。

  1. Model:它仅仅关注数据本身,不关心任何行为。Model 提供了应用程序所需的数据和业务逻辑。

  2. View:负责接收用户输入、发起数据请求及展示结果页面。在Android中,View 通常对应于Activity或Fragment。

  3. ViewModel:它是MVVM架构中的核心部分,负责业务逻辑处理,并将Model中的数据与View进行绑定。ViewModel不持有View的引用,而是通过数据绑定机制与View进行通信。

二、MVVM 原理

MVVM 的核心原理是实现View与Model的双向绑定,使得当Model中的数据发生变化时,View能够自动更新;同样,当View中的用户输入或操作导致数据变化时,Model也能同步更新。在Android中,这一原理通常通过Jetpack提供的LiveData、ViewModel等组件来实现。

三、MVVM 常见组件

  1. LiveData:一个可观察的数据持有者,它持有某个数据并允许数据绑定组件观察这个数据。当数据变化时,LiveData 会通知观察者。

  2. ViewModel:存储和管理UI相关的数据,即使配置发生变化(如屏幕旋转),数据也会保持不变。ViewModel负责将Model中的数据传递给View,并处理与数据相关的业务逻辑。

  3. Repository:负责数据的获取和存储,可以是网络请求、本地数据库或文件等。Repository通常作为Model的一部分,为ViewModel提供数据服务。

四、MVVM 常见用法

在Android开发中,MVVM架构模式通常用于构建复杂的应用程序,以提高代码的可维护性和可扩展性。以下是MVVM架构的常见用法:

  1. 数据绑定:通过LiveData和DataBinding库,实现View与ViewModel之间的数据绑定,使界面能够自动更新。

  2. 业务逻辑处理:将业务逻辑从View中分离出来,放入ViewModel中进行处理,以提高代码的可读性和可测试性。

  3. 配置变化处理:通过ViewModel保持数据在配置变化(如屏幕旋转)时的稳定性,避免重复的网络请求或数据计算。

五、Android开发实例

实例一:天气应用

在这个例子中,我们构建一个简单的天气应用,它能够从网络获取天气数据并显示在界面上。同时,用户可以通过点击按钮来更新天气信息。

  1. Model:定义一个数据类来表示天气信息,并通过Repository类来获取和存储天气数据。

  2. View:使用Activity或Fragment来展示天气信息,并包含一个按钮用于更新天气。

  3. ViewModel:包含一个LiveData对象来持有天气数据,并提供获取和更新天气数据的方法。

代码示例(简化版):

// Model(数据类)
data class Weather(val description: String)

// Repository(数据获取和存储)
class WeatherRepository {
    
    
    // 模拟网络请求获取天气数据
    fun getWeather(): Weather {
    
    
        // 省略网络请求代码,直接返回模拟数据
        return Weather("晴天")
    }
}

// ViewModel
class WeatherViewModel : ViewModel() {
    
    
    val weatherResult = MutableLiveData<Weather>()

    init {
    
    
        // 初始化时获取天气数据
        weatherResult.postValue(WeatherRepository().getWeather())
    }

    fun updateWeather(description: String) {
    
    
        // 更新天气数据
        weatherResult.postValue(Weather(description))
    }
}

// View(Activity)
class WeatherActivity : AppCompatActivity() {
    
    
    private lateinit var binding: ActivityWeatherBinding
    private lateinit var viewModel: WeatherViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        binding = ActivityWeatherBinding.inflate(layoutInflater)
        setContentView(binding.root)

        viewModel = ViewModelProvider(this).get(WeatherViewModel::class.java)

        binding.btnUpdateWeather.setOnClickListener {
    
    
            viewModel.updateWeather("阴天")
        }

        viewModel.weatherResult.observe(this, Observer {
    
     weather ->
            binding.tvWeather.text = weather.description
        })
    }
}

(注意:上述代码为简化版,实际开发中需要处理网络请求错误、生命周期管理等问题。)

实例二:用户列表应用

在这个例子中,我们将构建一个用户列表应用,该应用将从本地数据库(如Room数据库)中获取用户数据,并在RecyclerView中展示这些数据。我们将使用MVVM架构模式来实现这一功能。

1. Model层

首先,我们定义一个User数据类来表示用户信息,并创建一个UserDao接口来定义数据库操作。

// User.kt
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int,
    val name: String,
    val email: String
)

// UserDao.kt
@Dao
interface UserDao {
    
    
    @Query("SELECT * FROM User")
    fun getAllUsers(): LiveData<List<User>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertUser(user: User)

    // 其他数据库操作...
}
2. ViewModel层

接下来,我们创建一个UserViewModel类来处理与用户数据相关的业务逻辑。UserViewModel将包含一个LiveData<List<User>>对象来持有用户列表数据,并提供一个方法来刷新用户列表。

// UserViewModel.kt
class UserViewModel : ViewModel() {
    
    
    private val userRepository: UserRepository
    val allUsers: LiveData<List<User>>

    init {
    
    
        userRepository = UserRepository(UserDatabase.getDatabase(application).userDao())
        allUsers = userRepository.getAllUsers()
    }

    fun refreshUsers() {
    
    
        // 在这里可以添加逻辑来从服务器或其他数据源刷新用户数据,
        // 但在这个例子中,我们仅从本地数据库获取数据。
        // 由于我们使用的是LiveData,所以当数据库中的数据变化时,UI会自动更新。
    }

    // 清理资源(如果需要的话)
    override fun onCleared() {
    
    
        super.onCleared()
        // 可以在这里取消任何正在进行的网络请求或清理其他资源。
    }
}

// UserRepository.kt(可选,用于封装数据库操作)
class UserRepository(private val userDao: UserDao) {
    
    
    val allUsers: LiveData<List<User>> = userDao.getAllUsers()

    // 其他数据库操作封装...
}

注意:在这个例子中,我们创建了一个UserRepository类来封装数据库操作,但这并不是MVVM架构的必需部分。你可以直接在UserViewModel中调用UserDao的方法。

3. View层

最后,我们在Activity或Fragment中设置RecyclerView来展示用户列表,并观察UserViewModel中的allUsers数据。

// UserListActivity.kt
class UserListActivity : AppCompatActivity() {
    
    
    private lateinit var binding: ActivityUserListBinding
    private lateinit var userViewModel: UserViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        binding = ActivityUserListBinding.inflate(layoutInflater)
        setContentView(binding.root)

        userViewModel = ViewModelProvider(this).get(UserViewModel::class.java)

        binding.userRecyclerView.layoutManager = LinearLayoutManager(this)
        binding.userRecyclerView.adapter = UserAdapter()

        userViewModel.allUsers.observe(this, Observer {
    
     users ->
            // 更新RecyclerView的适配器数据
            (binding.userRecyclerView.adapter as UserAdapter).submitList(users)
        })

        // 可以在这里添加按钮或其他UI元素来调用userViewModel.refreshUsers()方法(如果需要的话)
    }

    // UserAdapter.kt(RecyclerView的适配器)
    class UserAdapter : ListAdapter<User, UserAdapter.UserViewHolder>(DiffCallback) {
    
    
        // DiffCallback的实现用于高效地更新RecyclerView中的数据
        private object DiffCallback : DiffUtil.ItemCallback<User>() {
    
    
            override fun areItemsTheSame(oldItem: User, newItem: User): Boolean = oldItem.id == newItem.id
            override fun areContentsTheSame(oldItem: User, newItem: User): Boolean = oldItem == newItem
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
    
    
            val itemView = LayoutInflater.from(parent.context)
                .inflate(R.layout.item_user, parent, false)
            return UserViewHolder(itemView)
        }

        override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
    
    
            val user = getItem(position)
            holder.bind(user)
        }

        class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    
    
            private val nameTextView: TextView = itemView.findViewById(R.id.nameTextView)
            private val emailTextView: TextView = itemView.findViewById(R.id.emailTextView)

            fun bind(user: User) {
    
    
                nameTextView.text = user.name
                emailTextView.text = user.email
            }
        }
    }
}

在这个例子中,我们创建了一个UserAdapter类来作为RecyclerView的适配器,并使用DiffUtil来高效地更新RecyclerView中的数据。我们还使用了Data Binding库来简化View与ViewModel之间的数据绑定。

请注意,上述代码示例是简化版的,实际开发中可能需要处理更多的细节,如错误处理、生命周期管理等。此外,为了完整性,可能还需要创建一个UserDatabase类来配置Room数据库,并在AndroidManifest.xml中声明必要的权限。

猜你喜欢

转载自blog.csdn.net/qq_36329049/article/details/143135442