博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MVI - 继续来凑个热闹
阅读量:6590 次
发布时间:2019-06-24

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

这几天掘金上铺天盖地的 MVI,但是看了都是用 mosby 写的,我就觉得费得用 mosby 吗?PublishSubject 简简单单的就能实现,本文例子是在以前的代码上改的,用的 java 大家见谅,另外欢迎喷,不喷不自在哈...


MVI 概念

MVI 是和 MVVM 一起出现的概念,是跟着 Rxjava 响应式思路衍生出来的一种想法

MVVM 我猜大家都熟悉,数据层传递 Livedata -> persenter -> 再到 UI 层去注册监听,这是个单向的过程,从 的过程:

一般 MVVM 我们都是这么写,但是也有的人写的更彻底,app 的交互是个双向过程,先从 再到 ,上面常见的方式我们只是实现了一边,更彻底的响应式改造是连点击事件都是响应式的,数据层注册监听按钮的点击事件,通过上水管道接受数据,远程数据返回后再通过下水管道返回数据:

一般没写这么麻烦的~

MVI 和双向 MVVM 的思路相同,区别就是 MVI 进一步抽象了 UI 的动作,也就是 MVI 中的 I - Intent,MVI 中把任何一个 UI 事件都看成一个响应式数据源,P 层的任务就是绑定注册 V 和 M 层的关系,就像热水器一样接通上下水管道:

MVI 中的这个 Intent 有自己的思想,Intent 把 UI 页面的任何变化都看成一个整体,用一个数据类型来表示,比如有一个 ViewState 对象里面有 loading,netError,success 各种表示页面状态的标志位,数据层返回的是这个 ViewState 而不再直接是数据了,UI 层根据 ViewState 的状态来显示不同的 UI 样式,这样 P 层就不用再写一堆控制 UI 显示状态的方法了,真正实现了 MVP 的分层思想,谁的事谁关心,当然 MVVM 也可以做到,但是一般 MVVM 里面都是直接返回数据的,真的把页面状态也封装进数据的没几个人

class NetViewState(        var loading: Boolean = false,        var success: Boolean = false,        var netError: Boolean = false,        var dataError: Boolean = false,        var dataNo: Boolean = false,        var message: String = "",        var data: BookResponse = BookResponse()) {    companion object Help {        @JvmStatic        fun loading(): NetViewState {            return NetViewState(loading = true)        }        @JvmStatic        fun success(data: BookResponse): NetViewState {            return NetViewState(success = true, data = data)        }        @JvmStatic        fun netError(message: String): NetViewState {            return NetViewState(netError = true, message = message)        }        @JvmStatic        fun dataError(message: String): NetViewState {            return NetViewState(dataError = true, message = message)        }        @JvmStatic        fun dataNo(message: String): NetViewState {            return NetViewState(dataNo = true,message = message)        }    }}复制代码

代码走起

MVI 我看了好多文章,都是借助 mosby 这个库来实现的,mosby 带来了大量的衍生类型,每个角色都有其基类,无形中大大增加了学习成本,MVI 本是 MVVM 思路的进一步而已,没想到大伙做的反倒是越来越复杂,全完没必要,简简单单的多好,还容易理解,容易阅读

使用 rxjava 热发射或是 Livedata 就可以简单的实现 MVI 了,我就不想用 mosby ,自己实现一个 MVI 出来,下面的 Demo 只是用来演示,更多的请自省封装,优化

Ui 层对外提供事件 Intent
protected void onCreate(Bundle savedInstanceState) {        btn_book.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                bookIntent.onNext(new BookRequest("人生", "", "0", "10"));            }        });        persenter.netActivity = this;        persenter.bingIntent(bookIntent);    }    void updata(NetViewState netViewState) {        if (netViewState.getLoading()) {            Log.d("AA", "loading ...");            return;        }        if (netViewState.getNetError()) {            Log.d("AA", " netError:" + netViewState.getMessage());        }        if (netViewState.getDataError()) {            Log.d("AA", " dataError:" + netViewState.getMessage());        }        if (netViewState.getSuccess()) {            List
books = netViewState.getData().getBooks(); if (books != null && books.size() == 0) { ToastComponent.Companion.getInstance().show("没有数据", Toast.LENGTH_SHORT); } adapter.refreshData(books); } }复制代码
M 层关注上游 UI 层事件,提供下游数据层观察者
public class BookRepositroy {    public static final String URL_BOOK_LIST = "book/search";    public PublishSubject
bookData = PublishSubject.create(); public void bingIntent(Observable
bookIntent) { bookIntent.subscribe(new Consumer
() { @Override public void accept(BookRequest bookRequest) throws Exception { getBookData(bookRequest); } }); } private void getBookData(BookRequest bookRequest) { Map
map = new HashMap<>(); map.put("q", bookRequest.getTitle()); map.put("tag", bookRequest.getTag()); map.put("start", bookRequest.getStartCount()); map.put("count", bookRequest.getWantCount()); HttpClient.Companion.getInstance().get(URL_BOOK_LIST, map) .map(new Function
() { @Override public NetViewState apply(ResponseBody responseBody) throws Exception { BookResponse bookResponse = null; try { bookResponse = new Gson().fromJson(responseBody.string(), BookResponse.class); } catch (Exception e) { Observable.error(e); } return NetViewState.success(bookResponse); } }) .onErrorReturn(new Function
() { @Override public NetViewState apply(Throwable throwable) throws Exception { if (throwable instanceof HttpException) { // HTTP错误 return NetViewState.netError("网络错误"); } else if (throwable instanceof ConnectException || throwable instanceof UnknownHostException) { // 连接错误 return NetViewState.netError("连接错误"); } else if (throwable instanceof InterruptedIOException) { // 连接超时 return NetViewState.netError("连接超时"); } else if (throwable instanceof JsonParseException || throwable instanceof JSONException || throwable instanceof ParseException) { return NetViewState.dataError("解析错误"); } else if (throwable instanceof ApiException) { return NetViewState.netError(throwable.getMessage()); } else if (throwable instanceof IOException) { return NetViewState.netError("网络错误"); } return NetViewState.netError("位置错误"); } }) .startWith(NetViewState.loading()) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(new Consumer
() { @Override public void accept(final NetViewState netViewState) throws Exception { bookData.onNext(netViewState); } }); }}复制代码
p 层绑定上下游(V 和 P)关系
public class NetPersenter {    public NetActivity netActivity;    BookRepositroy repositroy = new BookRepositroy();    public void bindBook(PublishSubject
bookIntent) { repositroy.bingIntent(bookIntent); repositroy.bookData.subscribe(new Consumer
() { @Override public void accept(NetViewState netViewState) throws Exception { netActivity.updata(netViewState); } }); }}复制代码
  • P 层注册下游数据而没有交给 V 层,是因为在 P 层里面我们可能有业务逻辑要要先一部处理,不能直接交给 U层
  • M 层使用 startWith 优先发送一个 loading 的事件出来
  • ViewState 这里可以进一步优化的,大部分页面的状态都一样,有必要抽象一个基类出来,而且使用 koltin 的密封类(sealed) 还可以做的更好,再说现在是 kotlin 的时代了,纯 java 的代码我都不应该贴出来,这还是因为这个页面还是以前写的在上面改的,要不我就 kotlin 了

最后

没几行代码,本来也是没打算写文章出来的,但是后来想想网上都是用 mosby 库写的 MVI,我写出来给大家提供另一种思路吧,能简单的何必更复杂呢

转载于:https://juejin.im/post/5ce12e0b6fb9a07eeb13787b

你可能感兴趣的文章
【斗医】【18】Web应用开发20天
查看>>
测试测试
查看>>
Android之API动画学习与扩展总结
查看>>
.NET3.0总体结构
查看>>
文件上传技巧汇总
查看>>
Windows 7 与 Ubuntu 10.04系统共存
查看>>
当scanf接收单字符遇上循环
查看>>
oracle 12c创建可插拔数据库(PDB)及用户
查看>>
AMH面板+wordpress搭建个人博客详细教程(下)
查看>>
解决rsyslog+loganalyzer不能同时显示IP和主机名(原创)
查看>>
wxWidgets利用tinyxml实现xml解析
查看>>
mysql主从同步和读写分离
查看>>
jconsole监控linux系统的jvm使用
查看>>
网络安全设计、配置与管理大全
查看>>
check outlook mailbox size
查看>>
什么是 stack?- 每天5分钟玩转 Docker 容器技术(111)
查看>>
java 泛型编程(一)
查看>>
Dell PowerEdge R940解析:四路顶配服务器维护平民化
查看>>
《数据重现》赠书活动开始
查看>>
Android 中文 API (93) —— BaseExpandableListAdapter
查看>>