Android MVP模式

看了下当初转载过的一篇关于mvp模式的介绍文章,后来有人反馈没有介绍Model层,且一直想整一个简单的mvp模式+databinding框架代替公司比较源生的代码写法。于是打算重新整理一下mvp模式思想的代码写法总结。

介绍下MVP模式:
M:Model层,数据服务层,负责数据的增删改查。在服务端就包括mysql数据库操作、本地cache等;在客户端就包括调用服务器API、各种形式的数据缓存等。有些朋友将Model层理解为数据模型层,数据模型归根结底是数据,设计数据模型是为了在面向对象的程序设计中更好的表达数据。所以数据模型贯穿于整个应用程序,不应该将Model层单单理解为是数据模型。但Model层往往负责将接收到的数据转化为相应的数据模型供上层使用。
V:View层,视图界面层,负责UI的渲染、子视图的组织、UI事件、用户交互等。在有些网友看来,View层是比较轻的一层,大多数时候只需要调用系统的UI控件,绑定需要的UI事件就完事了,很多平台甚至拖拖控件就行。但是实际上是因为平台为我们做了大多数的事,我们不需要去考虑怎么有效的渲染界面,也不需要去考虑怎样去实现各种各样的交互事件(触摸),只需要关注应用本身就可以了。
P:Presenter层,有得朋友将其叫作发布者,百度翻译为主持人,笔者觉得后者更贴切些。 Presenter既是中间人,在View和Model之间起到桥梁的作用,又是一个独立的大模块,封装了业务的复杂度,将UI和业务逻辑拆分开来,使UI和业务都可以独立的进行变化。从整体的数据流向上看,Presenter从Model层获取数据,并通过接口发送给View层展示;View层将用户交互传递给Presenter,由Presenter完成相应的业务逻辑,这其中可能会有Model层的参与,比如Presenter调用Model层的接口来保存数据。

实现MVP模式的最低原则是

  1. View和Model之间不能直接进行交互,必须通过Presenter来交流数据;
  2. 尽量的将业务逻辑和UI展示分开;
  3. 尽量使用面向接口的方式来实现MVP三层,特别是对于View与Presenter之间的交互。

参考:https://www.jianshu.com/p/31c3909ce075
MVP模式的作用

MVP的好处都有啥
1.分离了视图逻辑和业务逻辑,降低了耦合
2.Activity只处理生命周期的任务,代码变得更加简洁
3.视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
4.Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
5.把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM

强调一下,mvp模式是一种思想,并不是一种固定的写法,网上有很多例子。没有谁对谁错,更没有谁的是唯一标准。

下面我们通过一个登录例子来简单说明下:
首先写一个模拟网络请求的类:

  companion object {
        val instance by lazy(LazyThreadSafetyMode.NONE) {
            NetUtil()
        }
    }


    fun loginRequest(username: String, password: String?): Int {

        Log.d(TAG, "$username $password")
        SystemClock.sleep(3000)

        return 1


    }

Model
model层主要处理数据业务逻辑,所以我们将登录的网络请求放在model层处理

class LoginModel {

    lateinit var loginListener: (Int) -> Unit

    fun login(username: String, password: String, e: (Int) -> Unit) {
        loginListener = e
        LoginAsyncTask().execute(username, password)
    }

    inner class LoginAsyncTask : AsyncTask<String, Void, Int>() {
        override fun doInBackground(vararg params: String?): Int {

            return NetUtil.instance.loginRequest(params[0]!!, params[1]!!)
        }

        override fun onPostExecute(result: Int?) {
            super.onPostExecute(result)
            loginListener?.let {
                loginListener(result!!)
            }
        }
    }

}

写了一个简单的异步任务,将结果通过loginListener 暴露出去。这里,我们需要将数据反馈给Presenter层。
紧接着我们编写Presenter层,作为view层和model层的桥梁

Presenter

class LoginPresenter(iLoginView: ILoginView) {
    private var weakReference: WeakReference<ILoginView>
    private val loginModel: LoginModel?

    init {
        weakReference = WeakReference(iLoginView)
        loginModel = LoginModel()
    }

    fun getLoginRespond(userName: String, paw: String) {
        loginModel?.let {
            weakReference.get()?.apply {
                it.login(userName, paw) { label ->
                    weakReference.get()!!.onRespond(label)
                }
            }
        }


    }
}

View层
view层作为处理得到数据后ui的一些渲染更新等等,比较轻量级。用接口表示:

interface ILoginView {
    fun onRespond(response: Int)
}

Activity的使用

class LoginActivity : AppCompatActivity(), ILoginView {
    override fun onRespond(response: Int) {
        tv_login_result.text = if (response == 1) "登录成功" else "登录失败"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var username = et_username.text.toString()
        var password = et_paw.text.toString()
        tv_login.setOnClickListener {
            LoginPresenter(this@LoginActivity)
                .getLoginRespond(username, password)
        }
    }
}

以上就是简单的一个mvp代码的框架,再次强调一遍,mvp模式只是一种思想,并没有固定的写法,所以网上很多例子没有对错,只有适不适合和你对他们是否认可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342