MVP 写法 → MVVM

10 阅读1分钟

MVP 写法 → MVVM

老写法(Java — MVP)

// Contract
interface MainContract {
    interface View {
        void showUser(String name);
        void showLoading();
        void hideLoading();
        void showError(String msg);
    }
    interface Presenter {
        void loadUser();
        void detach();
    }
}

// Presenter
public class MainPresenter implements MainContract.Presenter {
    private MainContract.View view;

    public void attach(MainContract.View view) { this.view = view; }

    @Override
    public void loadUser() {
        view.showLoading();
        api.loadUser(new Callback<User>() {
            @Override
            public void onSuccess(User user) { view.showUser(user.getName()); view.hideLoading(); }
            @Override
            public void onError(String msg) { view.showError(msg); view.hideLoading(); }
        });
    }

    @Override
    public void detach() { view = null; }
}

问题在哪里

每个页面都要写 Contract 接口 + Presenter 实现,大量样板代码。Presenter 持有 View 引用需要手动 attach/detach,忘调用 detach 就会内存泄漏。测试 Presenter 需要 mock View 接口,如果接口有十几个方法就很痛苦。

新写法(MVVM + ViewModel)

// ViewModel — 不需要 Contract,不需要 View 接口
class MainViewModel(private val api: ApiService) : ViewModel() {

    private val _userName = MutableLiveData<String>()
    val userName: LiveData<String> = _userName
    private val _isLoading = MutableLiveData(false)
    val isLoading: LiveData<Boolean> = _isLoading

    fun loadUser() {
        viewModelScope.launch {
            _isLoading.value = true
            try {
                val user = withContext(Dispatchers.IO) { api.loadUser() }
                _userName.value = user.name
            } catch (e: Exception) {
                _error.value = e.message
            } finally {
                _isLoading.value = false
            }
        }
    }
}

一句话注意

从 MVP 切到 MVVM 最大的思维变化:Presenter 不主动调 View 的方法,而是 ViewModel 更新数据,View 自己观察数据变更来响应。这消除了 Presenter 对 View 的直接引用,不再需要 attach/detach 生命周期管理。

MVP 的 View 接口方法越多,MVVM 的收益越大——ViewModel 只暴露 LiveData/StateFlow 数据,不管谁在观察。View 层可以是一个 Activity、一个 Fragment、甚至是一个 Compose 页面,ViewModel 对它们一视同仁。


Java Android 老项目迁移系列,持续更新中。