在 MVVM(Model - View - ViewModel)架构中,M 层即 Model 层,主要负责数据的管理、存储和获取,它与业务逻辑和数据处理相关。在 Kotlin 中实现 MVVM 的 M 层,通常会涉及数据类的定义、数据的本地存储与远程获取等操作,以下是详细的实现讲解:
1. 定义数据类
数据类是 Kotlin 中非常方便的特性,用于简洁地定义数据模型。它会自动生成 equals()
、hashCode()
、toString()
等方法。以下是一个简单的用户数据类示例:
Kotlin
data class User(
val id: Int,
val name: String,
val age: Int,
val email: String
)
这个数据类 User
表示一个用户的基本信息,包含 id
、name
、age
和 email
四个属性。
2. 本地数据存储
如果需要将数据存储在本地,可以使用 Android 的 Room
数据库。Room
是 Android 官方提供的一个抽象层,用于在 SQLite 数据库上进行对象映射,结合 Kotlin 可以更方便地操作数据库。
2.1 定义实体类
首先,要确保数据类符合 Room
的实体类要求,添加 @Entity
注解:
Kotlin
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
val age: Int,
val email: String
)
这里的 @Entity
注解指定了该数据类对应数据库中的 users
表,@PrimaryKey
注解指定了 id
作为主键。
2.2 定义 DAO(数据访问对象)
DAO 用于定义数据库操作的方法,使用 @Dao
注解:
Kotlin
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface UserDao {
@Insert
suspend fun insertUser(user: User)
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUserById(id: Int): User?
}
在这个 DAO 中,@Insert
注解表示插入操作,@Query
注解用于自定义查询操作。注意方法使用了 suspend
关键字,以便在协程中调用。
2.3 定义数据库
使用 @Database
注解定义数据库:
Kotlin
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
这里指定了数据库包含的实体类为 User
,版本号为 1,并提供了获取 UserDao
的抽象方法。
3. 远程数据获取
如果需要从网络获取数据,可以使用 Retrofit
库。Retrofit
是一个类型安全的 HTTP 客户端,结合 Kotlin 协程可以高效地进行网络请求。
3.1 定义 API 接口
Kotlin
import retrofit2.http.GET
import retrofit2.http.Path
interface UserApiService {
@GET("users/{id}")
suspend fun getUserById(@Path("id") id: Int): User
}
这个接口定义了一个获取用户信息的方法,使用 @GET
注解指定请求的 URL,@Path
注解用于替换 URL 中的参数。
3.2 创建 Retrofit 实例
Kotlin
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
private const val BASE_URL = "https://example.com/api/"
val instance: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val userApiService: UserApiService by lazy {
instance.create(UserApiService::class.java)
}
}
这里创建了一个 Retrofit
实例,并通过 create()
方法创建了 UserApiService
的实例。
4. 仓库(Repository)模式
为了统一管理本地和远程数据的获取,通常会使用仓库模式。仓库类负责协调数据的来源,根据需要从本地数据库或远程服务器获取数据。
Kotlin
class UserRepository(
private val userDao: UserDao,
private val userApiService: UserApiService
) {
suspend fun getUserById(id: Int): User? {
// 先从本地数据库获取数据
var user = userDao.getUserById(id)
if (user == null) {
// 如果本地没有数据,从网络获取
user = userApiService.getUserById(id)
if (user != null) {
// 将从网络获取的数据保存到本地数据库
userDao.insertUser(user)
}
}
return user
}
}
在这个仓库类中,getUserById
方法首先尝试从本地数据库获取用户数据,如果本地没有则从网络获取,并将获取到的数据保存到本地数据库。
总结(M层)
通过以上步骤,我们在 Kotlin 中实现了 MVVM 架构的 M 层。主要包括数据类的定义、本地数据存储(使用 Room
)、远程数据获取(使用 Retrofit
)以及仓库模式的应用,这样可以有效地管理数据的来源和流向,提高代码的可维护性和可测试性。
下一层:V层
以下将详细介绍在 Kotlin 中实现 MVVM 架构里 V 层(View 层)的完整步骤,并给出相应代码示例。V 层主要负责展示 UI 以及处理用户交互,通常由 Activity 或 Fragment 实现。
项目准备
确保在 build.gradle
文件中添加必要依赖:
Kotlin
dependencies {
// ViewModel 和 LiveData
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
// ViewBinding
android {
buildFeatures {
viewBinding = true
}
}
// Kotlin 协程
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}
定义布局文件
在 res/layout
目录下创建 activity_main.xml
文件,用于定义界面布局
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入内容" />
<Button
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送" />
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:paddingTop="16dp" />
</LinearLayout>
创建 ViewModel
ViewModel 负责处理业务逻辑和数据管理,以下是 MainViewModel
的实现:
Kotlin
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MainViewModel : ViewModel() {
private val _result = MutableLiveData<String>()
val result: LiveData<String> = _result
fun processInput(input: String) {
// 简单处理输入,这里只是将输入内容反转
val processed = input.reversed()
_result.value = processed
}
}
创建 Activity 作为 V 层
使用 Kotlin 实现 MainActivity
作为 View 层,通过 ViewBinding 绑定视图,观察 ViewModel 中的数据变化并处理用户交互:
Kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.mvvmexample.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使用 ViewBinding 绑定布局
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 获取 ViewModel 实例
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// 设置按钮点击事件监听器
binding.btnSend.setOnClickListener {
// 获取输入框中的内容
val input = binding.etInput.text.toString()
// 调用 ViewModel 的方法处理输入
viewModel.processInput(input)
}
// 观察 ViewModel 中的数据变化
viewModel.result.observe(this, Observer { result ->
// 更新 UI 显示处理结果
binding.tvResult.text = "处理结果: $result"
})
}
}
代码解释
- ViewBinding 的使用 :
ActivityMainBinding.inflate(layoutInflater)
用于实例化绑定类,通过setContentView(binding.root)
设置布局,之后可直接使用binding
对象访问布局中的视图组件,如binding.etInput
、binding.btnSend
等。
- ViewModel 的获取 :
ViewModelProvider(this).get(MainViewModel::class.java)
用于获取MainViewModel
的实例,确保在 Activity 的生命周期内使用同一个 ViewModel 实例。
- 用户交互处理 :
- 通过
binding.btnSend.setOnClickListener
为按钮设置点击事件监听器,当按钮被点击时,获取输入框中的内容并调用 ViewModel 的processInput
方法进行处理。
- 通过
- 数据观察 :
viewModel.result.observe(this, Observer { ... })
用于观察LiveData
的数据变化,当LiveData
的值发生改变时,会触发Observer
中的代码块,从而更新 UI。
使用 Fragment 作为 V 层(可选)
如果使用 Fragment 作为 V 层,实现方式类似:
创建布局文件 fragment_main.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/et_input_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入内容" />
<Button
android:id="@+id/btn_send_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送" />
<TextView
android:id="@+id/tv_result_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:paddingTop="16dp" />
</LinearLayout>
创建 Fragment
Kotlin
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.mvvmexample.databinding.FragmentMainBinding
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// 使用 ViewBinding 绑定布局
_binding = FragmentMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 获取 ViewModel 实例
viewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
// 设置按钮点击事件监听器
binding.btnSendFragment.setOnClickListener {
val input = binding.etInputFragment.text.toString()
viewModel.processInput(input)
}
// 观察 ViewModel 中的数据变化
viewModel.result.observe(viewLifecycleOwner, Observer { result ->
binding.tvResultFragment.text = "处理结果: $result"
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
总结(V层)
通过以上步骤,我们可以在 Kotlin 中使用 Activity 或 Fragment 作为 MVVM 架构的 V 层,借助 ViewBinding 绑定视图,使用 ViewModelProvider
获取 ViewModel 实例,处理用户交互并观察 ViewModel 中的数据变化以更新 UI,实现视图和业务逻辑的分离,提高代码的可维护性和可测试性。
因为太多了,我就先讲解前两个层,下一节我将阐述最重要的VM层
谢谢观看!!!