最近MVP火的不要不要的,我也来凑盘热闹,其实MVP的文章看了好多了,但是一直还停留在概念阶段,这几天对Google Android的todoapp的代码进行了解析,然后使用Kotlin翻译了一下,算了对MVP有了一个大概的认识,那么MVP究竟是什么,网上一搜一大堆,我就把名字复述一下,MVP的全称为Model-View-Presenter,即模型-视图-协调器(主持者),最重要的功能还是解耦,代码也更容易扩展和维护,下面我们还是来看具体的例子:demo还是做一个干货的列表页:
先看目录结构,
Paste_Image.png
这里单独建了个MVP的包,base中定义了两个接口BaseView和BasePresenter
BaseView
package com.vslimit.kotlindemo.mvp.base /** * Created by vslimit on 17/1/6. */ interface BaseView<T> { fun setPresenter(presenter: T) }
BasePresenter
package com.vslimit.kotlindemo.mvp.base /** * Created by vslimit on 17/1/6. */ interface BasePresenter { fun start() }
实现Contract
GanksContract
package com.vslimit.kotlindemo.mvp.ganks import com.vslimit.kotlindemo.model.Gank import com.vslimit.kotlindemo.mvp.base.BasePresenter import com.vslimit.kotlindemo.mvp.base.BaseView /** * Created by vslimit on 17/1/10. */ interface GanksContract { interface View : BaseView<Presenter> { fun showGanks(ganks: List<Gank>) fun showTip(message:String) fun showLoading() fun hideLoading() } interface Presenter : BasePresenter { fun loadGanks() } }
接口中定义了需要实现想要展示的View,而Presenter处理交互,下面我们来看具体的实现类:
GanksPresenter
package com.vslimit.kotlindemo.mvp.ganks import com.vslimit.kotlindemo.model.Gank import com.vslimit.kotlindemo.model.GankListResult import com.vslimit.kotlindemo.service.RestfulService import com.vslimit.kotlindemo.service.ServiceFactory import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers /** * Created by vslimit on 17/1/11. */ class GanksPresenter : GanksContract.Presenter { var mGanksView: GanksContract.View? = null constructor(ganksView: GanksContract.View) { mGanksView = checkNotNull(ganksView) mGanksView!!.setPresenter(this) } override fun loadGanks() { mGanksView!!.showLoading() val service = ServiceFactory.createRetrofitService(RestfulService::class.java, RestfulService.GANK_SERVICE_ENDPOINT) service.loadGanks().subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : Subscriber<GankListResult>() { override fun onCompleted() { mGanksView!!.hideLoading() } override fun onError(e: Throwable) { mGanksView!!.showTip(e.toString()) } override fun onNext(result: GankListResult) { processGanks(result.results) } }) } override fun start() { loadGanks() } fun processGanks(ganks: List<Gank>) { mGanksView!!.showGanks(ganks) } }
这里只实现了一个交互,即从服务端获取ganks数据,获取数据的实现请参考之前的文章传送门,既然数据OK了,那我们就来看看View是如何展示的:
GanksFragment
package com.vslimit.kotlindemo.mvp.ganks import android.os.Bundle import android.support.v7.widget.LinearLayoutManager import android.view.View import com.vslimit.kotlindemo.R import com.vslimit.kotlindemo.adapter.BaseAdapter import com.vslimit.kotlindemo.extensions.loading import com.vslimit.kotlindemo.fragment.BaseFragment import com.vslimit.kotlindemo.model.Gank import com.vslimit.kotlindemo.util.Const import kotlinx.android.synthetic.main.fragment_ganks.* import kotlinx.android.synthetic.main.item_list_gank.view.* import org.jetbrains.anko.info import org.jetbrains.anko.onClick import org.jetbrains.anko.support.v4.act import org.jetbrains.anko.support.v4.toast /** * Created by vslimit on 17/1/10. */ class GanksFragment : BaseFragment(), GanksContract.View { override val layoutResourceId: Int = R.layout.fragment_ganks var mPresenter: GanksContract.Presenter? = null var adapter: BaseAdapter<Gank>? = null companion object { fun getInstance(): GanksFragment { return GanksFragment() } } override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val layoutManager: LinearLayoutManager = LinearLayoutManager(act) gankListRv.layoutManager = layoutManager adapter = BaseAdapter(R.layout.item_list_gank, arrayListOf()) { view: View, item: Gank -> view.item_gank_title.text = item.desc view.item_gank_who.text = item.who view.item_gank_date.text = item.publishedAt view.onClick { showTip("") } } gankListRv.adapter = adapter } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun hideLoading() { loading(Const.HIDE) } override fun showLoading() { loading(Const.SHOW) } override fun showTip(message: String) { toast(message) } override fun setPresenter(presenter: GanksContract.Presenter) { mPresenter = checkNotNull(presenter) info("demo") } override fun onResume() { super.onResume() mPresenter?.start() } override fun showGanks(ganks: List<Gank>) { adapter!!.items = ganks adapter!!.notifyDataSetChanged() } }
在这个fragment同样使用了之前文章封装的通用RecycleView.Adapter,有兴趣的朋友可以回头看看之前的文章传送门,最后我们来看看Activity都实现了什么:
GanksActivity
package com.vslimit.kotlindemo.mvp.ganks import android.os.Bundle import android.support.design.widget.NavigationView import android.support.v4.view.GravityCompat import android.support.v4.widget.DrawerLayout import android.view.MenuItem import com.vslimit.kotlindemo.R import com.vslimit.kotlindemo.activity.BaseActivity import com.vslimit.kotlindemo.ui.DrawerLayoutManager import org.jetbrains.anko.find /** * Created by vslimit on 17/1/10. */ class GanksActivity(override val layoutResourceId: Int = R.layout.activity_tasks) :BaseActivity(),DrawerLayoutManager{ override val drawerLayout by lazy { find<DrawerLayout>(R.id.drawer_layout) } val navigationView by lazy { find<NavigationView>(R.id.nav_view) } var mGanksPresenter: GanksPresenter? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupDrawerContent(navigationView, R.id.drawLayoutTask) val ganksFragment = GanksFragment.getInstance() if (savedInstanceState == null) { initFragment(ganksFragment) } mGanksPresenter = GanksPresenter(ganksFragment) } override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { android.R.id.home -> { drawerLayout.openDrawer(GravityCompat.START) return true } } return super.onOptionsItemSelected(item) } }
至此,基于Kotlin的MVP已经实现,从代码中不难看出,model与view实现了解耦,那么问题来了,是不是MVP适用于所有场景,就我个人的感觉,如果页面UI设计复杂,交互多,那应该使用MVP,这样,能达到解耦的目的和效果,并且便于以后的维护和扩展,但是,如果只是单一的交互,比如登录或者像本文的只是个列表展示或详情,那就直接用Activity和Fragment即可,毕竟杀鸡用牛刀确实有点小题大做的感觉;至于说项目中究竟用MVC还是MVP要看具体场景以及个人喜好。
哦,对了,效果图(懒得截图,就使用之前的了,不过点击按钮在侧滑菜单中,列表效果是一样的):
共同学习,写下你的评论
评论加载中...
作者其他优质文章