Kotlin + Mvp + RxJava + Retrofit 心得体会

1,745 阅读7分钟
原文链接: mp.weixin.qq.com

code小生,一个专注 Android 领域的技术平台

公众号回复 Android 加入我的安卓技术群

作者:Walkud链接:https://www.jianshu.com/p/4cb1a56acf9e声明:本文已获Walkud 授权发表,转发等请联系原作者授权

先上本项目 Github 地址:https://github.com/Walkud/JudyKotlinMvp

首先声明

本项目是参考 git-xuhao/KotlinMvp ,对原项目 Mvp 核心代码及 Adapter 代码按照自己的想法进行了重构,布局 (xml) 文件(除 fragment_mine.xml )、工具类、自定义 View 都直接使用的原项目的文件,本项目的主要目的是为了 Kotlin 学习,将自己对 Java 版 Mvp 的理解用 Kotlin 实现。

说明

我希望用尽可能少的文字和代码来说明是自己对 Mvp 的理解。

Mvp

Mvp 最主要的目的就是为了解耦,让各个模块各司其职。

M (Model)负责业务模型的构建,可简单理解为P所需要的数据结构就在这一层处理及封装(包括网络、Sqlite、sp等)。

可参考 MainModel ,Model的粒度根据实际情况自行控制。

P (Presenter)负责处理业务逻辑,可简单理解为业务中的UI操作、 if 判断等。

UI操作不仅仅是调用 UI 的数据更新操作,还包含何时显示进度框、隐藏进度框、绑定Ui生命周期等。

model.getSearchResult(keyWords!!)        .compose(NetTransformer())//异步调度(异步发起请求 --> 主线程回调)        .compose(ProgressTransformer(view))//进度框的显示与隐藏        .compose(bindUntilOnDestroyEvent())//绑定UI生命周期 (PS: 生命周期时机可控)        .subscribe(object : RxSubscribe<HomeBean.Issue>() {            ……        })

以上代码用三行代码进行了异步调度、进度框显示与隐藏控制、UI 的声明周期绑定(防止内存泄漏)操作,这就是 RxJava 魅力所在。

可参考 VideoDetailPresenter

V (View)负责提供 UI 交互的能力,可简单理解为 V 监听到用户的点击事件 --> P 处理业务逻辑 --> V 更新UI。

Activity、Fragment 为 V ,其中 Adapter、View(xml、自定义View)、Dialog 等为 V 的一部分,所有的交互事件都放在 Activity 和 Fragment 中进行监听,便于日后定位。

项目中 Mvp 实现

//依赖关系View  < —— > Presenter —— > Model

本项目中使用泛型来指定依赖关系,且直接依赖的具体实现,并没有依赖抽象,可以有效提高开发效率,但违背了设计原则,个人认为过于看重这些原则,导致开发效率降低也有些得不偿失。

//基类 V  (MvpFragment 同理)abstract class MvpActivity<P> : MvcActivity() {    val presenter: P by lazy {        getP()    }    /**     * 获取逻辑处理实例,子类实现     */    abstract fun getP(): P    …… }//具体实现class SearchActivity : MvpActivity<SearchPresenter>() {//泛型指定 P 的依赖关系    // 这里实例化 P 并且 注入 V    override fun getP() = SearchPresenter().apply { view = this@SearchActivity }}//基类 Popen class BasePresenter<V : Any, out M> : ViewLifecycle() {    /**     * UI视图,即Activity或Fragment     */    var view: V by Delegates.notNull()    /**     * 业务模型,即XXXModel,这里使用java反射(kotlin反射太慢,暂时不建议使用)创建示例,省去在每个Presenter中创建实例     */    val model: M by lazy {      //这里使用 Java 反射实例化 M,      ReflectionUtils.getSuperClassGenricType<M>(this, 1)    }    ……}//具体实现class SearchPresenter : BasePresenter<SearchActivity, MainModel>() {//泛型指定 V 和 M 的具体实现    ……}

通过上面代码,Mvp 之间的关系就建立起来了,需要注意的是 M 是通过Java 反射实例化的(省去在 P 的实现类中去实例化,直接使用即可),具体使用请参考代码。

MvpActivityBasePresenter

解决痛点

抽象(创建过多无用的接口)

之前用过 Mvp 的在这点上应该深有体会,直接依赖具体实现可以很好的解决这个问题,对于需要复用的地方也可以指定泛型为接口,从而达到可复用目的,实际项目中这种复用需求很少。

异步导致的内存泄漏

异步时间过长而界面已退出,回调中依然隐式的持有 Activity 实例,这个问题在开发中很常见,所以本项目中使用了 RxJava (异步利器)来处理异步问题,由于它的灵活性,在加上另外一位大神开源库 RxLifecycle 可以很方便的处理这个问题,而且使代码也非常美观(一行代码搞定),最重要的是处理时机可控(比如在 onStop 或 onDestory )。

//为了控制篇幅,偷懒了,参照前面贴的代码compose(bindUntilOnDestroyEvent())//绑定UI生命周期 (PS: 生命周期时机可控)

进度UI的控制

对于弹框进度、下拉刷新、上拉加载、异常布局等控制问题,使用 RxJava 可以完美的解决,一行代码解放开发者大脑,不需要再去想何时显示、何时隐藏。

//为了控制篇幅,偷懒了,参照前面贴的代码compose(ProgressTransformer(view))//进度框的显示与隐藏

ProgressTransformer

交互都由 Activity 或 Fragment 来处理

有没有同学遇到修改遗留 Bug 找某个点击事件的时候,要跳转 N 个类,最后发现事件监听里面发了一个 Event 事件,然后又得找是谁消费了事件,发现居然有 N 个类都有消费(一脸懵逼,我的真实遭遇。。。) ,本项目的处理方式是将最终的监听都放在 V 中 的 addListener 方法中,找交互事件的时候可以快速定位。

RxJava

RxJava 使代码更连贯、逻辑更清晰(特别是去看原来的代码)、简洁,项目中使用了 RxJava 优雅的解决了异步调度、进度框显示与隐藏控制、UI 的声明周期绑定的问题,使用简单灵活。

RxJava 对于初学者来说,算是一个比较难上手的库,网上也有很多文章,但看完之后也不知道哪里好用,哪里简洁。在这里分享一个我最初学习的方法:

  1. 先依葫芦画瓢,硬着头皮去使用,对 RxJava 有个初步的概念。

  2. 有了初步的概念,回头再去看文章会有不一样的体会,会理解作者在说什么,随便学习几个常用的操作符。

  3. 结合自己的理解,最好能从生活中找个例子对照理解。

  4. 学习理解更多的操作符及操作符示意图。

  5. fuck 源码、分享、写文章。

以上方法不适合所有人,以后有机会我也写写对 RxJava 的理解。

Retrofit

Retrofit 是一个遵循 RESTful 设计标准的一个网络请求封装库。

Retrofit 使用了大量的设计模式,其中动态代理 + 注解的思路来声明后端接口非常优雅,再加上提供网络请求适配器及数据转换器的扩展,基本上已满足大部分的业务需求了。

Retrofit简易流程图.jpg

上图是我整理的一个 Retrofit 简易流程图。Retrofit 源码推荐阅读,难度小,里面的技术知识非常多,可以在网上找篇源码分的文章结合着看。

总结

  • 分享自己对 Mvp 的理解。

  • 分享了如何优雅的解决异步调度、进度框显示与隐藏控制、UI 的声明周期绑定问题。

  • 说明项目 Mvp 关系的实现逻辑。

  • 说明项目解决的痛点。

  • 分享 RxJava 的学习方法。

  • 整理出 Retrofit 简易流程图。

有不同意见的可以通过留言或者Issues,项目中重构部分的代码注释比较完善,便于你查阅,谢谢!

本项目 Github 地址:JudyKotlinMvphttps://github.com/Walkud/JudyKotlinMvp