美文网首页
Android MVP模式

Android MVP模式

作者: 若无初见 | 来源:发表于2019-06-05 15:36 被阅读0次

看了下当初转载过的一篇关于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模式只是一种思想,并没有固定的写法,所以网上很多例子没有对错,只有适不适合和你对他们是否认可。

相关文章

网友评论

      本文标题:Android MVP模式

      本文链接:https://www.haomeiwen.com/subject/dsqjxctx.html