一、MVC (Model-View-Controller)
数据流向
User → View(点击) → Controller(Activity) → Model(数据/网络) → 回调更新 View
职责划分
| 角色 |
职责 |
| Model |
数据层(Bean、网络请求、数据库) |
| View |
XML + Activity(显示 + 交互监听) |
| Controller |
Activity(业务逻辑 + UI 更新) |
实现
// Model
public class UserModel {
public void login(String name, String pwd, Callback callback) {
api.login(name, pwd, callback);
}
}
// Activity = Controller + View
public class LoginActivity extends Activity {
private UserModel model;
private EditText etName, etPwd;
private Button btnLogin;
private TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
model = new UserModel();
btnLogin.setOnClickListener(v -> {
// Controller 处理逻辑
model.login(etName.getText().toString(),
etPwd.getText().toString(),
new Callback() {
@Override
public void onSuccess(User user) {
// Controller 直接更新 View
tvResult.setText("Success");
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
@Override
public void onError(String msg) {
tvResult.setText(msg);
}
});
});
}
}
| ✅ 优点 |
❌ 缺点 |
| 简单直观,容易理解 |
Activity 既当 C 又当 V |
| 适合小型项目 |
代码臃肿,难以维护 |
| 职责分离初步体现 |
View 和 Controller 耦合 |
|
单元测试困难 |
|
Model 直接操作 View |
| 推荐度 |
⭐ |
二、MVP (Model-View-Presenter)
数据流向
User → View(点击) → Presenter(中介) → Model(数据) → 回调 → Presenter → View 更新
职责划分
| 角色 |
职责 |
| Model |
数据层(网络、数据库、Bean) |
| View |
Activity/Fragment(纯 UI 展示 + 事件上报) |
| Presenter |
业务逻辑层(处理逻辑 + 调度 M/V) |
核心改进:View 和 Presenter 通过接口解耦,Presenter 可独立测试。
实现
// Contract 接口定义
public interface LoginContract {
interface View {
void showLoading();
void hideLoading();
void showError(String msg);
void navigateToMain();
}
interface Presenter {
void login(String name, String pwd);
void detachView();
}
}
// Presenter 实现
public class LoginPresenter implements LoginContract.Presenter {
private LoginContract.View view;
private LoginRepository repo;
public void attachView(LoginContract.View view) {
this.view = view;
}
@Override
public void login(String name, String pwd) {
if (view == null) return;
view.showLoading();
repo.login(name, pwd, new Callback() {
@Override
public void onSuccess() {
if (view != null) {
view.hideLoading();
view.navigateToMain();
}
}
@Override
public void onError(String msg) {
if (view != null) {
view.hideLoading();
view.showError(msg);
}
}
});
}
@Override
public void detachView() {
this.view = null; // 防止内存泄漏
}
}
// Activity 实现 View 接口
public class LoginActivity extends AppCompatActivity implements LoginContract.View {
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
presenter = new LoginPresenter(new LoginRepository());
presenter.attachView(this);
btnLogin.setOnClickListener(v -> {
presenter.login(etName.getText().toString(), etPwd.getText().toString());
});
}
@Override
protected void onDestroy() {
super.onDestroy();
presenter.detachView(); // 必须解绑,防内存泄漏
}
@Override
public void showLoading() { progressBar.setVisibility(View.VISIBLE); }
@Override
public void hideLoading() { progressBar.setVisibility(View.GONE); }
@Override
public void showError(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }
@Override
public void navigateToMain() { startActivity(new Intent(this, MainActivity.class)); }
}
| ✅ 优点 |
❌ 缺点 |
| View 和 Presenter 解耦 |
接口爆炸(IView/IPresenter) |
| Presenter 可独立测试 |
Presenter 持有 View 引用 |
| 职责清晰,代码分层 |
需手动管理生命周期 |
| 支持多 View 复用 P |
内存泄漏风险(未 detach) |
|
代码量增加 |
| 推荐度 |
⭐⭐ |
三、MVVM (Model-View-ViewModel) ⭐⭐⭐⭐⭐
数据流向
User → View(点击) → ViewModel(业务) → Model(数据) → 数据变化 → ViewModel → View 自动更新
(LiveData/Flow/DataBinding)
职责划分
| 角色 |
职责 |
| Model |
数据层(Repository + 网络 + 数据库) |
| View |
Activity/Fragment(纯 UI 观察数据变化) |
| ViewModel |
业务逻辑(处理数据 + 暴露 LiveData) |
核心改进:数据驱动,生命周期自动管理,无需手动 detach。
实现
// ViewModel
public class LoginViewModel extends ViewModel {
private MutableLiveData<UiState> uiState = new MutableLiveData<>();
private LoginRepository repo;
public LoginViewModel(LoginRepository repo) {
this.repo = repo;
}
public LiveData<UiState> getUiState() {
return uiState;
}
public void login(String name, String pwd) {
uiState.setValue(UiState.loading());
repo.login(name, pwd, new Callback() {
@Override
public void onSuccess() {
uiState.setValue(UiState.success());
}
@Override
public void onError(String msg) {
uiState.setValue(UiState.error(msg));
}
});
}
}
// Activity 观察数据
public class LoginActivity extends AppCompatActivity {
private LoginViewModel vm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
vm = new ViewModelProvider(this,
new LoginViewModelFactory(new LoginRepository())
).get(LoginViewModel.class);
// 自动观察数据变化
vm.getUiState().observe(this, state -> {
if (state.isLoading()) {
showLoading();
} else if (state.isSuccess()) {
navigateToMain();
} else if (state.isError()) {
showError(state.getMsg());
}
});
btnLogin.setOnClickListener(v -> {
vm.login(etName.getText().toString(), etPwd.getText().toString());
});
}
}
| ✅ 优点 |
❌ 缺点 |
| 生命周期自动管理 |
ViewModel 可能过重 |
| 数据驱动,自动更新 |
DataBinding 调试困难 |
| ViewModel 可复用 |
学习成本较高 |
| 单元测试方便 |
简单场景过度设计 |
| Jetpack 原生支持 |
|
| 无需手动 detach |
|
| 推荐度 |
⭐⭐⭐⭐⭐ |
四、MVI (Model-View-Intent)
数据流向
User → Intent(意图) → ViewModel 处理 → Model(Reducer) → 不可变 State → View渲染新 State
职责划分
| 角色 |
职责 |
| Intent |
用户意图(Click/Refresh/LoadMore) |
| ViewModel |
处理 Intent,调用 Model,生成新 State |
| State |
不可变状态(UI 完整快照) |
| View |
纯渲染函数(State → UI 映射) |
核心改进:单向数据流,不可变 State,状态可预测,支持时间旅行调试。
实现
// 不可变 State
public class LoginState {
public final boolean isLoading;
public final String error;
public final User user;
public final boolean isLoggedIn;
public LoginState(boolean isLoading, String error, User user, boolean isLoggedIn) {
this.isLoading = isLoading;
this.error = error;
this.user = user;
this.isLoggedIn = isLoggedIn;
}
// 工厂方法生成新状态
public static LoginState idle() {
return new LoginState(false, null, null, false);
}
public static LoginState loading() {
return new LoginState(true, null, null, false);
}
public static LoginState success(User user) {
return new LoginState(false, null, user, true);
}
public static LoginState error(String msg) {
return new LoginState(false, msg, null, false);
}
}
// Intent 枚举
public enum LoginIntent {
LOGIN_CLICK,
USERNAME_CHANGED,
PASSWORD_CHANGED
}
// ViewModel
public class LoginViewModel extends ViewModel {
private MutableLiveData<LoginState> state = new MutableLiveData<>(LoginState.idle());
private LoginRepository repo;
public LiveData<LoginState> getState() {
return state;
}
public void processIntent(LoginIntent intent, String... params) {
switch (intent) {
case LOGIN_CLICK:
handleLogin(params[0], params[1]);
break;
case USERNAME_CHANGED:
// 处理用户名变化
break;
case PASSWORD_CHANGED:
// 处理密码变化
break;
}
}
private void handleLogin(String name, String pwd) {
state.setValue(LoginState.loading());
repo.login(name, pwd, new Callback() {
@Override
public void onSuccess(User user) {
state.setValue(LoginState.success(user));
}
@Override
public void onError(String msg) {
state.setValue(LoginState.error(msg));
}
});
}
}
// Activity
public class LoginActivity extends AppCompatActivity {
private LoginViewModel vm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
vm = new ViewModelProvider(this).get(LoginViewModel.class);
vm.getState().observe(this, state -> {
render(state); // 纯渲染函数
});
btnLogin.setOnClickListener(v -> {
vm.processIntent(LoginIntent.LOGIN_CLICK,
etName.getText().toString(),
etPwd.getText().toString());
});
}
private void render(LoginState state) {
progressBar.setVisibility(state.isLoading ? View.VISIBLE : View.GONE);
if (state.error != null) {
tvError.setText(state.error);
tvError.setVisibility(View.VISIBLE);
} else {
tvError.setVisibility(View.GONE);
}
if (state.isLoggedIn) {
startActivity(new Intent(this, MainActivity.class));
}
}
}
| ✅ 优点 |
❌ 缺点 |
| 单向数据流,状态可预测 |
样板代码多 |
| 不可变 State,调试友好 |
State 类膨胀 |
| 时间旅行调试 |
简单场景过度设计 |
| 状态复现简单 |
学习曲线陡峭 |
| 适合复杂交互场景 |
每个 Intent 都需定义 |
| 推荐度 |
⭐⭐⭐⭐ |
五、四大架构模式对比总结
| 维度 |
MVC |
MVP |
MVVM |
MVI |
| 数据流向 |
双向 |
双向 |
双向/响应式 |
单向 |
| View 更新 |
Controller 直接操作 |
Presenter 回调 |
LiveData 自动 |
State 不可变渲染 |
| 生命周期 |
手动管理 |
手动 detach |
自动管理 |
自动管理 |
| 单元测试 |
困难 |
较容易 |
容易 |
容易 |
| 代码量 |
少 |
多(接口) |
中等 |
多(State/Intent) |
| 内存泄漏 |
高 |
中(需 detach) |
低 |
低 |
| 适用场景 |
小型 Demo |
中小型项目 |
中大型项目 |
复杂交互/状态多 |
| 推荐度 |
⭐ |
⭐⭐ |
⭐⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
六、选型建议
- 新项目:首选 MVVM(Jetpack 原生支持,生态成熟)
- 状态复杂/团队协作:选 MVI(状态可预测,调试友好)
- 遗留项目维护:用 MVP(逐步迁移)
- 避免 MVC(Activity 臃肿,难以维护)