MVC
MVC 是指模型(model)- 视图(View)- 控制器(controller)
- Model:负责数据的加载和存储。
- View:负责界面数据的显示,与用户进行交互。
- Controller:负责逻辑业务的处理。
View 接受用户的请求,然后将请求传递给 Controller,Controller 进行业务逻辑处理后,通知 Model 去更新,Model 数据更新后,通知 View 去更新界面显示。在 Android 项目中,一般由 Activity 充当 Controller,XML 文件作为 View 层,Model 层即为数据结构和相关的类。

这里统一使用 wanandroid 开放 api
interface NetApi {
@GET("/hotkey/json")
suspend fun getHotKey(): Response?
companion object {
private const val BASE_URL = "https://www.wanandroid.com/"
fun createApi(): NetApi =
Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())
.build().create(NetApi::class.java)
}
}
data class HotWords(
val id: String,
val name: String,
)
data class Response(
val errorCode: Int,
val errorMsg: String,
val data: List<HotWords>
)
全篇需要用到的依赖有
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
创建 Model 层,请求数据。
class HttpModel {
suspend fun getData() =
try {
val result = NetApi.createApi().getHotKey()
if (result != null && !result.data.isNullOrEmpty()) {
result.data.toString()
} else {
NO_DATA
}
} catch (e: Exception) {
e.toString()
}
}
View 层很简单,就一个 TextView,用来显示返回的结果。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/result_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Controller 层通常为 Activity 或 Fragment,需要在其中进行逻辑处理。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
}
private fun initView() {
val resultText = findViewById<TextView>(R.id.result_text)
lifecycleScope.launch {
val httpText = HttpModel().getData()
resultText.text = httpText
}
}
}
MVC 模式的优点就是简单方便,但是它的缺点也比较明显,随着界面的增多和逻辑复杂度的提高,Activity 会显得十分臃肿,维护起来比较困难。
MVP
MVP,全称 Model - View - Presenter
- View:对应于 Activity,负责 View 的绘制和用户交互。
- Model:实体模型。
- Presenter:负责完成 View 和 Model 之间的交互。
MVC 中 V 对应的是布局文件,MVP 中 V 对应的是 Activity
使用 Presenter 作为 View 与 Model 之间的桥梁,当 View 层需要展示数据时,首先会调用 Presenter 的引用,然后 Presenter 层会调用 Model 层请求数据,当 Model 层数据加载成功之后,Presenter 层再调用 View 层的接口将数据展示给用户。

创建 MainContracts,集中管理 View 和 Presenter 。
class MainContracts {
interface IView {
// View 层获取数据回调方法
fun onResultData(data: String)
fun onResultFail(exp: String)
}
interface IPresenter {
// View 层向 Presenter发送请求方法
suspend fun requestData()
}
}
Presenter 层,在此进行网络请求,可以弱化 Model 的作用。
class MainPresenter(private var iView: MainContracts.IView) : MainContracts.IPresenter {
override suspend fun requestData() {
try {
val result = NetApi.createApi().getHotKey()
if (result != null && !result.data.isNullOrEmpty()) {
iView.onResultData(result.data.toString())
} else {
iView.onResultData(NO_DATA)
}
} catch (e: Exception) {
iView.onResultFail(e.toString())
}
}
}
View 层,通过接口获取数据。
class MainActivity : AppCompatActivity(), MainContracts.IView {
private lateinit var resultText: TextView
private val mainPresenter: MainPresenter by lazy {
MainPresenter(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
resultText = findViewById(R.id.result_text)
lifecycleScope.launch {
mainPresenter.requestData()
}
}
override fun onResultData(data: String) {
resultText.text = data
}
override fun onResultFail(exp: String) {
resultText.text = exp
}
}
MVP 通过 Presenter 实现数据和视图之间的交互,将复杂的逻辑代码提取到 Presenter 中进行处理,简化了 Activity 的职责,同时避免了 View 和 Model 的直接联系,又通过 Presenter 实现两者之间的沟通,降低了耦合度。不过,它也存在着缺点,随着项目复杂度的提升,Activity 或 Fragment 会不断增加,Presenter 层对应的接口和实现类会爆炸式地增长,Presenter 层就会越来越臃肿。
MVVM
- Model:数据层,包含数据实体和对数据实体的操作。
- View:界面层,对应于 Activity,XML,View,负责数据显示以及用户交互。
- ViewModel:关联层,将 Model 和 View 进行绑定,Model 或 View 更改时,实时刷新对方。

View 层接收用户操作,并通过持有的 ViewModel 去处理业务逻辑,请求数据,ViewModel 层通过 Model 去获取数据,然后 Model 又将最新的数据传回 ViewModel 层,到这里,ViewModel 与 Presenter 所做的事几乎是一样的。但是 ViewModel 不会持有 View 层的引用,而是 View 层会通过观察者模式监听 ViewModel 层的数据变化,当有数据更新时,View 层能自动收到新的数据并刷新界面。
打开 dataBinding
android {
...
buildFeatures {
dataBinding true
}
}
界面中使用 dataBinding 进行数据绑定
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="result"
type="String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{result}" />
</LinearLayout>
</layout>
ViewModel 层,进行网络数据请求。
class MainViewModel : ViewModel() {
private val resultLiveData = MutableLiveData<String>()
fun getData() {
viewModelScope.launch {
try {
val result = NetApi.createApi().getHotKey()
if (result != null && !result.data.isNullOrEmpty()) {
resultLiveData.value = result.data.toString()
} else {
resultLiveData.value = NO_DATA
}
} catch (e: Exception) {
resultLiveData.value = e.toString()
}
}
}
fun getResultLiveData() = resultLiveData
}
Activity 中监听 ViewModel 层的数据变化
class MainActivity : AppCompatActivity() {
private val mainViewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding =
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
mainViewModel.getData()
mainViewModel.getResultLiveData().observe(this) {
binding.result = it
}
}
}
MVVM 解耦得更彻底,在 MVP 模式中,Presenter 需要持有 View 的引用,才能去刷新 UI,在 MVVM 模式中,View 和 Model 使用 DataBinding 进行双向绑定,一方改变会直接通知另一方,使得 ViewModel 能专注于业务逻辑的处理,而无需关心 UI 的刷新。MVVM 不会像 MVC 一样导致 Activity 中代码量巨大,也不会像 MVP 一样出现大量的 View 接口。
但是,MVVM 也有些缺点:
- 调试难度增加:DataBinding 通过 XML 绑定数据,当 UI 展示异常时,问题可能出在数据逻辑,绑定表达式或生命周期管理中,定位问题比直接在代码中操作 UI 更间接。
- 状态管理复杂度:当页面状态复杂,ViewModel 需要维护大量的状态变量。若缺乏统一的状态管理策略,可能导致状态逻辑混乱,难以维护。
- 过度设计与代码冗余:对于简单场景(如一个仅展示静态内容的页面),MVVM 的分层设计会显得冗余,增加不必要的类和接口,反而不如直接使用传统模式高效。