? 在 MVVM(Model - View - ViewModel)架構中,M 層即 Model 層,主要負責數據的管理、存儲和獲取,它與業務邏輯和數據處理相關。在 Kotlin 中實現 MVVM 的 M 層,通常會涉及數據類的定義、數據的本地存儲與遠程獲取等操作,以下是詳細的實現講解:
1. 定義數據類
數據類是 Kotlin 中非常方便的特性,用于簡潔地定義數據模型。它會自動生成?equals()
、hashCode()
、toString()
?等方法。以下是一個簡單的用戶數據類示例:
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
?注解:
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
?注解:
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query@Dao
interface UserDao {@Insertsuspend fun insertUser(user: User)@Query("SELECT * FROM users WHERE id = :id")suspend fun getUserById(id: Int): User?
}
在這個 DAO 中,@Insert
?注解表示插入操作,@Query
?注解用于自定義查詢操作。注意方法使用了?suspend
?關鍵字,以便在協程中調用。
2.3 定義數據庫
使用?@Database
?注解定義數據庫:
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 接口
import retrofit2.http.GET
import retrofit2.http.Pathinterface UserApiService {@GET("users/{id}")suspend fun getUserById(@Path("id") id: Int): User
}
這個接口定義了一個獲取用戶信息的方法,使用?@GET
?注解指定請求的 URL,@Path
?注解用于替換 URL 中的參數。
3.2 創建 Retrofit 實例
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactoryobject 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)模式
為了統一管理本地和遠程數據的獲取,通常會使用倉庫模式。倉庫類負責協調數據的來源,根據需要從本地數據庫或遠程服務器獲取數據。
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
?文件中添加必要依賴:
dependencies {// ViewModel 和 LiveDataimplementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'// ViewBindingandroid {buildFeatures {viewBinding = true}}// Kotlin 協程implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}
定義布局文件
在?res/layout
?目錄下創建?activity_main.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"><EditTextandroid:id="@+id/et_input"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="請輸入內容" /><Buttonandroid:id="@+id/btn_send"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="發送" /><TextViewandroid:id="@+id/tv_result"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"android:paddingTop="16dp" />
</LinearLayout>
創建 ViewModel
ViewModel 負責處理業務邏輯和數據管理,以下是?MainViewModel
?的實現:
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelclass MainViewModel : ViewModel() {private val _result = MutableLiveData<String>()val result: LiveData<String> = _resultfun processInput(input: String) {// 簡單處理輸入,這里只是將輸入內容反轉val processed = input.reversed()_result.value = processed}
}
創建 Activity 作為 V 層
使用 Kotlin 實現?MainActivity
?作為 View 層,通過 ViewBinding 綁定視圖,觀察 ViewModel 中的數據變化并處理用戶交互:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.mvvmexample.databinding.ActivityMainBindingclass MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBindingprivate lateinit var viewModel: MainViewModeloverride 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 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"><EditTextandroid:id="@+id/et_input_fragment"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="請輸入內容" /><Buttonandroid:id="@+id/btn_send_fragment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="發送" /><TextViewandroid:id="@+id/tv_result_fragment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"android:paddingTop="16dp" />
</LinearLayout>
?創建 Fragment
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.FragmentMainBindingclass MainFragment : Fragment() {private var _binding: FragmentMainBinding? = nullprivate val binding get() = _binding!!private lateinit var viewModel: MainViewModeloverride 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層
謝謝觀看!!!