MVP MVVM

Jetpack MVP MVVM

[[MVI学习]]

QQ截图20191218104245

MVC

(Model-View-Controller)
M 是指逻辑模型,V 是指视图模型,C 则是控制器。通过 controller 的控制去操作 model 层的数据,并且返回给 view 层展示。一个逻辑模型可以对于多种视图模型。

Android 中也可以说采用了当前比较流行的 MVC 框架,在 Android 中: 

  1. 视图层(View):一般采用 XML 文件进行界面的描述,使用的时候可以非常方便的引入,但是用 xml 编写了,又需要在 Acitvity 声明并且实例化。
  2. 控制层(Controller):控制层的通常落在了众多的 Acitvity 的肩上,要通过 Activity 交割 Model 业务逻辑层处理,并且 activity 还充当了 view 层职责。
  3. 模型层(Model):java bean、对数据库的操作、对网络等的操作都应该在 Model 里面处理,当然对业务计算等操作也是必须放在的该层的。

MVP

MVP 就是基于 MVC 的模式上的一个演化版本。在 MVC 模式中,Activity 应该是属于 View 这一层。而实质上,它既承担了 View,同时也包含一些 Controller 的东西在里面。随着项目的迭代更新,这对开发很不友好,耦合度也原来越高,项目越来越难维护,而 MVP 就是解决这样的痛点。

MVP 的 model 层相对于 MVC 是一样的,而 activity 和 fragment 不再是 controller 层,而是纯粹的 view 层,所有关于用户事件的转发全部交由 presenter 层处理。

代理模式,交给另一个类做功能。

  1. view 层: View 对应于 Activity 或者 fragment,负责 View 的绘制以及与用户交互
  2. Presenter 负责完成 View 于 Model 间的交互
    • 本地存储数据,如数据库,文件,SharedPreferences(本质也是文件)
    • 内存的缓存或临时数据
    • 通过各种网络协议获取的远程数据

管理 Presenter 的生命周期

何时取消网络请求
如果 acitivity 已经关闭了, 而网络操作又没走完. 就会内存泄漏. view 虽然持有 p, 但是也不能在 Activity 的 onDestroy 里面直接的将 p=null 吧,对象=null 也只是断开引用而已,还并不是真的释放。
所以得有个接口告诉 p, 我要挂了, 你也自杀吧,所以:

1
2
3
4
interface BasePresenter {
  void onStart();
   void onDestroy();
}

让所有的 Presenter 都继承 BasePresenter, 然后在 activity(onDestory ())/fragment(onDestoryview ())中相应的生命周期里面调用,在相应的方法里面, 初始化, 结束异步操作, 释放资源, 将 view=null; 而在 activity 里面, 由于 Presenter 并没有 view 的引用了, 所以 p 随着 activity 的销毁也就跟着销毁了.不会造成泄漏等。
在 MVP 中我是在 BaseActivity 中统一把请求取消掉了

MVP 优点

  1. Model 与 View 完全分离,彻底解耦
  2. Presenter 复用,可以将一个 Presenter 用于多个视图,而不用改变 Presenter 的逻辑
  3. 可以实现 View 接口进行逻辑测试(Presenter 的单元测试)

MVP 的缺点

  1. Model 层过大,做好模块划分,进行接口隔离,在内部进行分层。
  2. MVP 额外的增加了很多类和接口, 这个可以根据项目业务进行相应地优化。划分 v/p 比较麻烦,一个 activity 引用了 v 以后,那得把 v 里面的方法都实现,即使没有用到.
  3. V 层与 P 层还是有一定的耦合度。一旦 V 层某个 UI 元素更改,那么对应的接口就必须得改,数据如何映射到 UI 上、事件监听接口这些都需要转变,牵一发而动全身。如果这一层也能解耦就更好了。(其他 mvc 也可以做到,看上面的 demo)
  4. 当 View 层在卸载时,如果 Model 层中仍有业务 (如子线程未完成、网络请求超时等)没有结束,而 Presenter 层中持有 Model 层和 View 层的引用,那么即使 View 的引用已经释放,由于 Presenter 层的强引用 GC 也无法回收它们。

mvp 中 presenter 的内存泄漏如何解决?

  • 弱引用 (WeakReference)的使用: 在 Presenter 中,避免直接持有对 View 层的强引用,而是使用 WeakReference 来代替。这样当 View 层被销毁时,WeakReference 会自动变为 null,垃圾回收器可以正常回收相应的内存。
  • 合理管理生命周期: 在 Activity 或 Fragment 的生命周期中,适时地创建和销毁 Presenter 对象。例如,可以在 Activity 的 onCreate 方法中创建 Presenter,在 onDestroy 方法中销毁 Presenter。这样可以确保当 Activity 被销毁时,Presenter 也能被正确释放。
  • 取消耗时任务: 如果在 Activity 中启动了耗时的任务 (如网络请求),在 Activity 销毁时需要确保这些任务被取消。这可以通过在 Activity 的 onDestroy 方法中取消请求来实现。

写一个 MVP 例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
       public interface HomeView {
        //显示加载页
        void showProgress();
        //关闭加载页
        void hideProgress();
        //加载新数据
        void newDatas(Book book);
        //显示加载失败
        void showLoadFailMsg();
    }


    public class HomeFragment implements HomeView {
        private HomePresenter homePresenter;
        protected void loadData() {
            homePresenter = new HomePresenter(this);
            homePresenter.getDataResults(1);
        }

        @Override
        public void newDatas(Book book) {}

        @Override
        public void showProgress() {}

        @Override
        public void hideProgress() {}
    }


    public class HomePresenter  implements OnLoadDataListListener<Book> {
        private HomeView mView;
        private Model mModel;

        public HomePresenter(HomeView mView) {
            this.mView = mView;
            this.mModel=new Model();
            mView.showProgress();
        }

        public void getDataResults(int page) {
            mModel.loadData(page,this);
        }

        @Override
        public void onSuccess(Book book) {
            mView.newDatas(book);
            mView.hideProgress();
        }

        @Override
        public void onFailure(Throwable e) {
            Log.e("onFailure",e.toString());
            mView.showLoadFailMsg();
        }
    }


    public class Model {
        public void loadData(final OnLoadDataListListener listener,int page) {
            HttpData.getInstance().getHomeInfo(page,new Observer<BOKKK>() {
                @Override
                public void onError (Throwable e) {
                    listener.onFailure (e);
                }

                @Override
                public void onResult (Book book) {
                    listener.onSuccess (book);
                }
            });
        }
    }

MVVM

如何构建Android MVVM 应用框架 - 美团技术团队

[[LiveData、ViewModel]]

官方图
unknown_filename.6|600

  • MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。
  • 图中所有的箭头都是单向的,比方说 Activity 指向了 ViewModel,表示》Activity 是依赖于 ViewModel 的,但是反过来 ViewModel 不能依赖于 Activity。其他的几层也是一样的道理,一个箭头就表示一个依赖关系。
    依赖关系是不可以跨层的,比方说 UI 控制层不能和仓库层有依赖关系,每一层的组件都只能和它的相邻层交互。

由于 livedata 当更新 viewmodel 层的数据的时候,view 层会相应的变动 ui。

1
UserModel model = ViewModelProviders.of (this). get (UserModel. class);

MVP MVVM
http://peiniwan.github.io/2024/04/3d467a5da044.html
作者
六月的雨
发布于
2024年4月6日
许可协议