MVC
MVC是 Model-View-Controller 的简称。
- M:模型层(Model) 负责与数据库和网络层通信,并获取和存储应用的数据;
- V:视图层(View) 负责将 Model 层的数据做可视化的处理,同时处理与用户的交互;
- C:控制层(Controller) 用于建立Model层与View层的联系,负责处理主要的业务逻辑,并根据用户操作更新 Model 层数据。
在 Android 项目的 MVC 架构中由于 Activity 同时充当了 View 层与 Controller 层两个角色,所以 Android 中的 MVC 更像下面的这种结构:
Model层
LogingListener是一个接口:
public interface LoginListener {
void onSuccess(User data);
void onFailed(String msg);
}
public class LoginModel {
public void login(String username, String password, LoginListener listener) {
RetrofitManager.getApiService()
.login(username, password)
.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
listener.onSuccess(response.data);
}
@Override
public void onFailed(Exception e) {
listener.onFailed(e.getMessage());
}
});
}
}
Controller/View层
public class MainActivity extends AppCompactActivity implements LoginListener {
private LoginModel loginModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
model = new LoginModel();
findViewbyId(R.id.btn_fetch_data).setOnClickListener(view -> {
String username = findViewById(R.id.et_username).getText().toString();
String password = findViewById(R.id.et_password).getText().toString();
loginModel.login(username, password, this);
}
);
}
@Override
public void onSuccess(User data) {
// Update UI
}
@Override
public void onFailed(String msg) {
// Update UI
}
}
不足:
- Android中的MVC代码对于分层并不明确,导致了Controller层与View层混为一体。
- Model 层与 View 层存在耦合,存在相互依赖关系。
- 开发时不注重分层,Model层代码也被塞进了Activity/Fragment,使得代码层次更加混乱。
MVP
针对以上MVC架构中存在的问题,我们可以在MVC的基础上进行优化解决。
- 即从Activity中剥离出控制层的逻辑,并阻断Model层与View层的耦合。
- Model层不直接与View通信,而是在数据改变时让 Model通知控制控制层,控制层再通知View层去做界面更新,这就是MVP的架构思想。
- M:模型层(Model) 与MVC中的一致,同样是负责与数据库和网络层通信,并获取和存储应用的数据,区别在于Model层不再与View层直接通信,而是与Presenter层通信。
- V:视图层(View) 负责将 Model 层的数据做可视化的处理,同时与Presenter层交互。跟MVC相比,MVP的View层与Model层不再耦合。
- P:控制层(Presenter) 主要负责处理业务逻辑,并监听Model层数据改变,然后调用View层刷新UI。
MVP 的结构图如下图所示:
从上图中可以看出:
- View直接与Presenter层通信,当View层接收到用户操作后会调用 Presenter层去处理业务逻辑。
- Presenter层通过Model去获取数据,Model层获取到数据后又将最新的数据传回 Presenter。
- 而Presenter层又持有View层的引用,进而将数据传给
View
层进行展示。
Model层
LogingListener是一个接口:
public interface LoginListener {
void onSuccess(User data);
void onFailed(String msg);
}
public class LoginModel {
public void login(String username, String password, LoginListener listener) {
RetrofitManager.getApiService()
.login(username, password)
.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
listener.onSuccess(response.data);
}
@Override
public void onFailed(Exception e) {
listener.onFailed(e.getMessage());
}
});
}
}
Presenter 层代码
- 由于 Presenter 需要通知 View 层更新UI,因此需要持有View。
- Presenter也需要与Model层通信,因此Presenter层也会持有Model层。
- 在用户触发登录操作后,调用Presenter的登录逻辑,Presenter通过Model进行登录操作,根据登录结果反馈给View层做不同的更新操作。
此时可将,view中的更新方法抽象出一个 View 接口 ,在View中实现这个接口。
public interface ILoginView {
void showLoading();
void dismissLoading();
void loginSuccess(User data);
void loginFailer(String errorMsg);
}
public class LoginPresenter {
// Model 层
private LoginModel model;
// View 层
private ILoginView view;
public LoginPresenter(LoginView view) {
this.model = new LoginModel();
this.view = view;
}
public void login(String username, String password) {
view.showLoading();
model.login(username, password, new LoginListener() {
@Override
public void onSuccess(User user) {
view.loginSuccess(user);
view.dismissLoading();
}
@Override
public void onFailed(String msg) {
view.loginFailer(msg);
view.dismissLoading();
}
});
}
@Override
public void onDestory() {
// recycle instance.
}
}
View 层代码
- 在View中实现更新View的接口
- 在View中持有Presenter来处理业务逻辑
public class MainActivity extends AppCompatActivity implements ILoginView {
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
presenter = new LoginPresenter(this);
findViewById(R.id.button).setOnClickListener(v -> {
String username = findViewById(R.id.et_username).getText().toString();
String password = findViewById(R.id.et_password).getText().toString();
presenter.login(username, password);
});
}
@Override
public void loginSuccess(User user) {
// Update UI.
}
@Override
public void loginFailer(String msg) {
// Update UI.
}
@Override
protected void onDestroy() {
super.onDestroy();
presenter.onDestroy();
}
@Override
public void showLoading() {
}
@Override
public void dismissLoading() {
}
}
MVP的本质是面向接口编程,实现依赖倒置原则。可以看得出来MVP架构在分层上相比 MVC更加清晰明确,且解耦了Model层与View层。但MVP也存在一些弊端。
不足:
- 引入大量的 IView、IPresenter接口实现类,增加项目的复杂度。
- View 层与 Presenter 相互持有,存在耦合。
MVVM
MVVM是 ** Model-View-ViewModel** 的简称。
- M:模型层(Model) 与MVP中的Model层一致,负责与数据库和网络层通信,获取并存储数据。与MVP的区别在于Model层不再通过回调通知业务逻辑层数据改变,而是通过观察者模式实现。
- V:视图(View) 负责将Model层的数据做可视化的处理,同时与ViewModel层交互。
- VM:视图模型(ViewModel) 主要负责业务逻辑的处理,同时与 Model 层 和 View层交互。与MVP的Presenter相比,ViewModel不再依赖View,使得解耦更加彻底。
MVVM架构的本质是数据驱动,它的最大的特点是单向依赖。MVVM架构通过观察者模式让ViewModel与View解耦,实现了View依赖ViewModel,ViewModel依赖Model的单向依赖。
观察者模式
自定义观察者
- 实现观察者接口
public interface Observer<T> {
// 成功的回调
void onSuccess(T data);
// 失败的回调
void onFailed(String msg);
}
- 抽象被观察者
public abstract class Observable<T> {
// 注册观察者
void register(Observer observer);
// 取消注册
void unregister(Observer observer);
// 数据改变(设置成功数据)
protected void setValue(T data) {
}
// 失败,设置失败原因
void onFailed(String msg);
}
- 被观察者具体实现
public class LoginObservable implements Observable<User> {
private final List<Observer<User>> list = new ArrayList<>();
private User user;
@Override
public void register(Observer<User> observer) {
list.add(observer);
}
@Override
public void unregister(Observer<User> observer) {
liset.remove(observer);
}
@Override
public void setValue(User user) {
this.user = user;
for (Observer observer : list) {
observer.onSuccess(user);
}
}
@Override
public void onFailed(String msg) {
for (Observer observer : list) {
observer.onFailed(msg);
}
}
}
Model层
Model层最大的特点是被赋予了数据获取的职责,与我们平常Model层只定义实体对象的行为截然不同。
实例中,数据的获取、存储、数据状态变化都是Model层的任务。Model包括实体模型(Bean)、Retrofit的Service ,获取网络数据接口,本地存储(增删改查)接口,数据变化监听等。
Model提供数据获取接口供ViewModel调用,经数据转换和操作并最终映射绑定到View层某个UI元素的属性上。
public class LoginModel {
public void login(String username, String password, LoginObservable observable) {
RetrofitManager.getApiService()
.login(username, password)
.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
observable.setValue(response.data);
}
@Override
public void onFailed(Exception e) {
observable.onFailed(e.getMessage());
}
});
}
}
ViewModel层
ViewModel层需要持有Model层,并且ViewModel层持有一个LoginObservable,并开放一个getObservable的方法供View层使用。
public class LoginViewModel {
private LoginObservable observable;
private LoginModel loginModel;
public LoginViewModel() {
loginModel = new LoginModel();
observable = new LoginObservable();
}
public void login(String username, String password) {
loginModel.login(username, password, observable);
}
// 这里返回值是父类Observable,即View层得到的Observable无法调用setValue
public Observable getObservable() {
return observable;
}
}
View层
View层持有ViewModel,用户触发登录事件通过View层交给Model处理,Model层在登录成后将数据交给ViewModel中的观察者。
因此,View层只需要获取到ViewModel层的观察者并观察到数据改变后更新UI即可。
public class MainActivity extends AppCompatActivity implements Observer<User> {
private LoginViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewModel = new LoginViewModel();
viewModel.getObservable().register(this);
findViewById(R.id.button).setOnClickListener(v -> {
String username = findViewById(R.id.et_username).getText().toString();
String password = findViewById(R.id.et_password).getText().toString();
viewModel.login(username, password);
});
}
@Override
public void onDestroy() {
super.onDestory();
viewModel.getObservable().unregister(this);
}
@Override
public void onSuccess(User user) {
// fetch data success,update UI.
}
@Override
public void onFailed(String message) {
// fetch data failed,update UI.
}
}
Jetpack组件实现 MVVM模式
为了实现MVVM架构,Google提供了一套强大的Jetpack组件,包括LiveData、ViewModel和Data Binding等。这些组件可以帮助开发人员更轻松地实现MVVM架构,并提供了许多现代化的开发工具和技术。
LiveData
Android --- LiveData-CSDN博客