博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android MVP,MVVM
阅读量:5862 次
发布时间:2019-06-19

本文共 6708 字,大约阅读时间需要 22 分钟。

hot3.png

一:先说MVC:原文连接:

  1. M层:适合做一些业务逻辑处理,比如数据库存取操作,网络操作,复杂的算法,耗时的任务等都在model层处理。
  2. V层:应用层中处理数据显示的部分,XML布局可以视为V层,显示Model层的数据结果。
  3. C层:在Android中,Activity处理用户交互问题,因此可以认为Activity是控制器,Activity读取V视图层的数据(eg.读取当前EditText控件的数据),控制用户输入(eg.EditText控件数据的输入),并向Model发送数据请求(eg.发起网络请求等)。

二、再说MVP:原文连接:

01095016_mRtC.jpg

  • Presenter 中同时持有 View 以及 ModelInterface 引用,而 View 持有 Presenter 的实例。

  • 当某个 View 需要展示某些数据时,首先会调用 Presenter 的某个接口,然后 Presenter 会调用 Model 请求数据。

  • Model 数据加载成功后会调用 Presenter 的回调方法通知 Presenter 数据加载完毕,最后 Presenter 再调用 View 层接口展示加载后数据。

不太爱用mvp。mvp无非就是面向接口编程的一个典型。presenter通过view和model接口的引用,来调用具体实现类实现的方法,这么做的好处是,业务结构清晰,且将来更换实现类超级方便,因为业务结构不用改,就只是实现类摘掉,再换一个就是。虽然明知好处,但还是不太爱用~

最后:

采用哪种软件设计模式都是为了达到如下目的:

易于维护

易于测试

松耦合度

复用性高

健壮稳定

三、MVVM:

原文连接:

MVVM是Model-View-ViewModel的简写. 它是有三个部分组成:Model、View、ViewModel。

Model:数据模型层。包含业务逻辑和校验逻辑。

View:屏幕上显示的UI界面(layout、views)。

ViewModel:View和Model之间的链接桥梁,处理视图逻辑。

MVVM图如下:

MMVM pattern

MVVM架构通过ViewModel隔离了UI层和业务逻辑层,降低程序的耦合度。通过DataBinding实现View和ViewModel之间的绑定。

Android App 中MVC的不足

一般来说,我们开发 App是基于MVC,由于MVC的普及和快速开发的特点,一个app从0开发一般都是基于MVC的。

Activity、Fragment相当于C (Controller), 布局相当于V(View), 数据层相当于M(Model)

松耦合具体带来的好处是:

随着业务的增长,Controller里的代码会越来越臃肿,因为它不只要负责业务逻辑,还要控制View的展示。也就是说Activity、Fragment杂糅了Controller和View,耦合变大。并不能算作真正意义上的MVC。

编写代码基本的过程是这样的,在Activity、Fragment中初始化Views,然后拉取数据,成功后把数据填充到View里。

假如有如下场景

我们基于MVC开发完第一版本,然后企业需要迭代2.0版本,并且UI界面变化比较大,业务变动较小,怎么办呢? 

当2.0的所有东西都已经评审过后。这个时候,新建布局,然后开始按照新的效果图,进行UI布局。然后还要新建Activity、Fragment把相关逻辑和数据填充到新的View上。 
如果业务逻辑比较复杂,需要从Activity、Fragment中提取上个版本的所有逻辑,这个时候自己可能就要晕倒了,因为一个复杂的业务,一个Activity几千行代码也是很常见的。千辛万苦做完提取完,可能还会出现很多bug。

MVP架构图如下:

这里写图片描述

MVP把视图层抽象到View接口,逻辑层抽象到Presenter接口,提到了代码的可读性。降低了视图逻辑和业务逻辑的耦合。

但是有MVP的不足:

  1. 接口过多,一定程度影响了编码效率。其实这也不算是不足,为了更好的分层解耦,这也是必须的。
  2. 导致Presenter的代码量过大。

这个时候MVVM就闪亮登场了。从上面的MVVM功能图我们知道:

  1. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。 
    在Android中,布局里可以进行一个视图逻辑,并且Model发生变化,View也随着发生变化。
  2. 低耦合。以前Activity、Fragment中需要把数据填充到View,还要进行一些视图逻辑。现在这些都可在布局中完成(具体代码请看后面) 
    甚至都不需要再Activity、Fragment去findViewById。这时候Activity、Fragment只需要做好的逻辑处理就可以了。

现在我们回到上面从app1.0到app2.0迭代的问题,如果用MVVM去实现那就比较简单,这个时候不需要动Activity、Fragment, 

只需要把布局按照2.0版本的效果实现一遍即可。因为视图逻辑和数据填充已经在布局里了,这就是上面提到的可重用性。

A view component in MVP contains a visual part of the application.

The view binds to observable variables and actions exposed by the view model typically using the data binding framework.

The view is responsible for handling for example:

  • Menus

  • Permissions

  • Event listeners

  • Showing dialogs, Toasts, Snackbars

  • Working with Android View and Widget

  • Starting activities

  • All functionality which is related to the Android Context

The view model contains the data required for the view. It is an abstraction of the view and exposes public properties and commands. It uses observable data to notify the view about changes. It also allows to pass events to the model. It is also a value converter from the raw model data to presentation-friendly properties)

The view model has the following responsibilities:

  • Exposing data

  • Exposing state (progress, offline, empty, error, etc)

  • Handling visibility

  • Input validation

  • Executing calls to the model

  • Executing methods in the view

The view model should only know about the application context. the application context can:

  • Start a service

  • Bind to a service

  • Send a broadcast

  • Register a broadcast receiver

  • Load resource values

It cannot:

  • Show a dialog

  • Start an activity

  • Inflate a layout

Contains a data provider and the code to fetch and update the data. The data can be retrieved from different sources, for example:

  • REST API

  • Realm db

  • SQLite db

  • Handles broadcast

  • Shared Preferences

  • Firebase

  • etc.

Basically the same as the model in the MVP.

四、MVVM BroadcastReceiver

I have a class WifiManager that holds a Boolean value that represents either wifi connected or wifi disconnected.

the Boolean field gets updated with a broadcastReceiver I have in that class.

private BroadcastReceiver wifiScanReceiver;private boolean isWifiConnected = false;wifiScanReceiver = new BroadcastReceiver() {            @Override            public void onReceive(Context c, Intent intent) {                    // Wifi connected/disconnected                    NetworkInfo nwInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);                    final WifiInfo connectionInfo = wifiManager.getConnectionInfo();                    if (nwInfo.getState().equals(NetworkInfo.State.CONNECTED)) {                        // wifi connect                        isWifiConnected = true;                    } else {                        // wifi disconnected                        isWifiConnected = false;                    }                }        };        context.registerReceiver(wifiScanReceiver, wifiIntentFilter);

In my MainActivity I have a WifiManager field, and what I want is to do data binding that will change one of the menu items based on the Boolean value -> if isWifiConnected=false set icon to @drawalbe/xxx, if isWifiConnected=true set icon to @drawalbe/yyy.

Meaning - having sort of a "listener" to changes of the isWifiConnected value, and based on that - set one of the MenuItem's icon to either @drawalbe/xxx or @drawalbe/yyy.

I know there are tons of ways to do it, from broadcasting an Intent in the BroadcastReceiver and catch it in the MainActivity to just have a Handler running and checking the isWifiConnectedevery 3 seconds..

What I am really looking for is sort of data binding with a converter, like you would do in a MVVM project.

Is there such a thing in android?

1 Answer

 

I assume you know about android data binding and you're just asking how to do it for this specific case. If not, here is the .

You will need a way to observe the boolean value so the UI can remain updated. The easiest way is to make it an ObservableBoolean field of your model object:

public class ViewModel {    public final ObservableBoolean isWifiConnected = new ObservableBoolean();    // other things you want to bind to your layout...}

When you create the binding, you must also assign the model:

public void onCreate(Bundle icicle) {    ActivityMainBinding binding =        DataBindingUtil.setContentView(this, R.layout.activity_main);    this.model = new ViewModel();    binding.setModel(this.model);}

And when you receive the broadcast, you update the model:

wifiScanReceiver = new BroadcastReceiver() {        //...        model.isWifiConnected.set(newValue);        //...    };

And your layout would be something like this:

You could also avoid the model class if you keep track of the binding and set the variable directly on it. In that case, you'd have a variable:

And your broadcast receiver would set the value:

binding.setIsWifiConnected(newValue);

 

 

 

转载于:https://my.oschina.net/u/1389206/blog/1525731

你可能感兴趣的文章
什么是DDOS攻击?怎么防御?
查看>>
状态模式(State Pattern)
查看>>
log4j日志框架学习
查看>>
function 与 => 的区别
查看>>
VBScript:写excel的例子
查看>>
TYVJ P1077 有理逼近 Label:坑,tle的好帮手 不懂
查看>>
面试题:缓存Redis与Memcached的比较 有用
查看>>
通过UIWebView加载读取本地文件
查看>>
由于缺少证书链,导致Android手机提示网站不安全
查看>>
EXCEL自动撤销合并单元格并填充相应内容(转帖)
查看>>
Glide图片框架
查看>>
Python3学习笔记10-条件控制
查看>>
Nginx 1.2.6 稳定版发布
查看>>
黄聪:如何使用CodeSmith批量生成代码(原创系列教程)
查看>>
Deep Learning(深度学习)学习笔记整理系列之(三)
查看>>
close_wait状态的产生原因及解决(转)
查看>>
测试用例设计方法-等价类划分法【转】
查看>>
HDOJ---1421 搬寝室[DP]
查看>>
用 Electron 和 React 撸了个功能超全 + 颜值极高的音乐客户端
查看>>
说说Chrome插件从开发调试到打包发布
查看>>