Android 架构模式

发布于:2024-06-30 ⋅ 阅读:(125) ⋅ 点赞:(0)

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博客

DataBinding


网站公告

今日签到

点亮在社区的每一天
去签到