造一个mvp的轮子

前言:虽然现在已经mvvm了,但是mvp对于新鸟来说,还是一个不错的入门级开发框架,这里就造一个lifecycle的mvp。

起初:mvp的轮子有很多了。大多数情况下是在activity/fragment的生命周期绑定presenter,然后在生命周期内初始化,或者释放,我这个轮子也没有什么特别的地方,也是遵循这一套,最近在看了MvpArm的源码设计后,由于本人太菜,不太会dagger2,又很欣赏arm中以lifecycle绑定presenter的做法,所以将dagger2抽离,造了个简易的lifecycle绑定presenter的轮子

这是MVPArms,个人觉得这确实是个不错的快速开发框架,里面集成了基本全部的开发所需,而且作者还提供了插件,掌握的话,可以节约很多开发时间和改bug时间来干自己想干的事

找工作.jpg

BaseActivity/BaseFragment

直接上代码


/**
 * baseActivity基类
 * 视图层,可自行拓展沉浸式等
 * 如果定义增多,建议新增IActivity接口以做规范
 */
abstract class BaseActivity : RxAppCompatActivity(), LifecycleObserver {
    private var mUnbinder: Unbinder? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(getLayout())
        mUnbinder = ButterKnife.bind(this)
        if (useEventBus()) {
            //register event
        }
        initView()
    }

    /**
     * 布局的layout
     */
    abstract fun getLayout(): Int

    /**
     * 是否使用eventBus
     */
    abstract fun useEventBus(): Boolean

    /**
     * 视图回调,这里是子类的开始
     */
    abstract fun initView()

    override fun onDestroy() {
        super.onDestroy()
        if (mUnbinder != null && mUnbinder !== Unbinder.EMPTY) {
            mUnbinder!!.unbind()
        }
        mUnbinder = null
        if (useEventBus()) {
            // unRegister event
        }
    }
}

BaseFragment同理,这两个基类是基础继承,在不使用mvp的时候,直接继承即可,base的作用不必多说,里面可以封装自己项目的逻辑

然后是

BaseMvpActivity(BaseMvpFragment)


/**
 * mvp
 */
abstract class BaseMvpActivity<P : IPresenter> : BaseActivity(), IView {
    private var mPresenter: P? = null

    /**
     * onCreate中创建presenter
     */
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mPresenter = setUpPresenter()
    }

    /**
     * 默认不使用eventBus
     */
    override fun useEventBus(): Boolean {
        return false
    }

    abstract fun setUpPresenter(): P?

    override fun onDestroy() {
        super.onDestroy()
        mPresenter?.onDestroy()
        mPresenter = null
    }

    var mStatusView: MultipleStatusView? = null
    override fun showLoading() {
        if (mStatusView == null) {
            val mViewRoot = window.decorView.findViewById<ViewGroup>(android.R.id.content).getChildAt(0) as ViewGroup
            if (mViewRoot.childCount != 0) {
                for (i in 0 until mViewRoot.childCount) {
                    if (mViewRoot.getChildAt(i) is MultipleStatusView) {
                        mStatusView = mViewRoot.getChildAt(i) as MultipleStatusView
                        mStatusView?.setOnRetryClickListener {
                            onReLoad()
                        }
                        break
                    }
                }
            }
        }
        mStatusView?.showLoading()
    }

    override fun showEmpty() {
        mStatusView?.showEmpty()
    }

    override fun showError() {
        mStatusView?.showEmpty()
    }

    override fun hideLoading() {
        mStatusView?.showContent()
    }

    var mAlertDialog: AlertDialog? = null
    override fun showDialogLoading() {
        mAlertDialog = AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog)
            .setView(R.layout.load_dialog_layout)
            .setCancelable(true).show()
    }

    override fun hideDialogLoading() {
        mAlertDialog?.dismiss()
    }

    override fun onReLoad() {

    }


    override fun showMessage(tipMessage: String?) {
        //Toast this
        Toast.makeText(this, tipMessage, Toast.LENGTH_SHORT).show()
    }

    override fun findActivity(): RxAppCompatActivity {
        return this
    }

    override fun findFragment(): RxFragment? {
        return null
    }
}

BaseMvpActivity/BaseMvpFragment处理presenter的创建,和资源的释放销毁

BasePresenter


/**
 * @author chenke
 * @create 2020/6/30
 * @Describe
 */
public class BasePresenter<M extends IModel, V extends IView> implements IPresenter, LifecycleObserver {
    protected CompositeDisposable mCompositeDisposable;
    protected M mModel;
    protected V mRootView;

    /**
     * 如果当前页面同时需要 Model 层和 View 层,则使用此构造函数(默认)
     *
     * @param model
     * @param rootView
     */
    public BasePresenter(M model, V rootView) {
        this.mModel = model;
        this.mRootView = rootView;
        onStart();
    }

    /**
     * 如果当前页面不需要操作数据,只需要 View 层,则使用此构造函数
     *
     * @param rootView
     */
    public BasePresenter(V rootView) {
        this.mRootView = rootView;
        onStart();
    }

    public BasePresenter() {

    }

    @Override
    public void onStart() {
        //将 LifecycleObserver 注册给 LifecycleOwner 后 @OnLifecycleEvent 才可以正常使用
        if (mRootView != null && mRootView instanceof LifecycleObserver) {
            //activity ,fragment绑定自身生命周期
            ((LifecycleOwner) mRootView).getLifecycle().addObserver(this);
            if (mModel != null && mModel instanceof LifecycleObserver) {
                //activity ,fragment绑定model数据层的生命周期,当Activity销毁时,数据层感知其生命周期
                ((LifecycleOwner) mRootView).getLifecycle().addObserver((LifecycleObserver) mModel);
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy(LifecycleOwner owner) {
        /**
         * 注意, 如果在这里调用了 {@link #onDestroy()} 方法, 会出现某些地方引用 {@code mModel} 或 {@code mRootView} 为 null 的情况
         * 比如在 {@link RxLifecycle} 终止 {@link Observable} 时, 在 {@link io.reactivex.Observable#doFinally(Action)} 中却引用了 {@code mRootView} 做一些释放资源的操作, 此时会空指针
         * 或者如果你声明了多个 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 时在其他 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
         * 中引用了 {@code mModel} 或 {@code mRootView} 也可能会出现此情况
         */
        owner.getLifecycle().removeObserver(this);
    }

    public void addDispose(Disposable disposable) {
        if (mCompositeDisposable == null) {
            mCompositeDisposable = new CompositeDisposable();
        }
        mCompositeDisposable.add(disposable);//将所有 Disposable 放入容器集中处理
    }

    /**
     * 停止集合中正在执行的 RxJava 任务
     */
    public void unDispose() {
        if (mCompositeDisposable != null) {
            mCompositeDisposable.clear();//保证 Activity 结束时取消所有正在执行的订阅
        }
    }

    @Override
    public void onDestroy() {
        unDispose();
        if (mModel != null) {
            mModel.onDestroy();
        }
        this.mModel = null;
        this.mRootView = null;
    }
}

activity/fragment 绑定了将生命周期和BasePresenter/Model,绑定,这样当activity/fragment生命周期法伤变化是,,base和model作为观察者

可以,观察到生命周期的变化

核心代码


    @Override
    public void onStart() {
        //将 LifecycleObserver 注册给 LifecycleOwner 后 @OnLifecycleEvent 才可以正常使用
        if (mRootView != null && mRootView instanceof LifecycleObserver) {
            //activity ,fragment绑定自身生命周期
            ((LifecycleOwner) mRootView).getLifecycle().addObserver(this);
            if (mModel != null && mModel instanceof LifecycleObserver) {
                //activity ,fragment绑定model数据层的生命周期,当Activity销毁时,数据层感知其生命周期
                ((LifecycleOwner) mRootView).getLifecycle().addObserver((LifecycleObserver) mModel);
            }
        }
    }

所以BasePresenter和model都要实现lifecycle的观察者接口

public class BasePresenterimplements IPresenter, LifecycleObserver
open class BaseModel : IModel, LifecycleObserver

因为model为数据交互层,所以需要retrofit的实例

BaseModel


/**
 * @author chenke
 * @create 2020/6/30
 * @Describe
 */
open class BaseModel : IModel, LifecycleObserver {
    protected var mRepositoryManager: IRepositoryManager? = null

    /**
     * model层为数据层,所以需要retrofit实例来请求网络
     */
    constructor(repositoryManager: IRepositoryManager) {
        this.mRepositoryManager = repositoryManager
    }

    /**
     * presenter在onDestroy时调用
     * 释放资源
     */
    override fun onDestroy() {
        mRepositoryManager = null
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy(owner: LifecycleOwner) {
        owner.lifecycle.removeObserver(this)
    }
}

现在,我们就用这个简易的生命周期感知mvp来写一个demo吧

界面如下


界面.jpg

xml就忽略了

WeatherActivity mvp的网络请求界面


class WeatherActivity : BaseMvpActivity<TestPresenter>(), TestContact.TestView {

    override fun setUpPresenter(): TestPresenter? {
        return TestPresenter(TestModel(RepositoryManager()), this)
    }

    override fun initView() {

    }

    override fun getLayout(): Int {
        return R.layout.activity_weather_activty
    }


    override fun bindTest(): TextView {
        return tv_content
    }
}

题外话:因为presenter在setContentView初始化,所以在presenter调用时TextView已经完成了初始化

presenter

presenter的创建

    override fun setUpPresenter(): TestPresenter? {
        return TestPresenter(TestModel(RepositoryManager()), this)
    }

这里RepositoryManager是retrofit的实例创建类

RepositoryManager

/**
 * @author chenke
 * @create 2020/6/30
 * @Describe retrofit网络创建层
 */
public class RepositoryManager : IRepositoryManager {

    private val URL_1 = "http://wthrcdn.etouch.cn/"

    var retrofit1 = Retrofit.Builder()
        .baseUrl(URL_1)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build()


    fun <T> create(serviceClass: Class<T>): T = retrofit1.create(serviceClass)

    private var apiHost1: ApiHost1? = null
    override fun getApiHost1(): ApiHost1 {
        if (apiHost1 == null) {
            apiHost1 = create(ApiHost1::class.java)
        }
        return apiHost1 as ApiHost1
    }

    override fun getApiHost2() {

    }

    override fun getApiHost3() {

    }


}

IRepositoryManager是管理retrofit url接口文件,可以将不同模块的url做拆分,也可以建立不同的baseurl(不同baseurl的retrofit客户端,或者针对每个url接口文件的baseurl通过常量来管理请求)

/**
 * @author chenke
 * @create 2020/6/30
 * @Describe
 */
interface IRepositoryManager {
    /**
     * 对应不同的baseUrl
     */
    fun getApiHost1(): ApiHost1

    fun getApiHost2()

    fun getApiHost3()
}

TestPresente

constructor(model: TestContact.TestModel, rootView: TestContact.TestView) :super(model, rootView)

我们再回过头来看super(model,rootView)

    /**
     * 如果当前页面同时需要 Model 层和 View 层,则使用此构造函数(默认)
     *
     * @param model
     * @param rootView
     */
    public BasePresenter(M model, V rootView) {
        this.mModel = model;
        this.mRootView = rootView;
        onStart();
    }
    @Override
    public void onStart() {
        //将 LifecycleObserver 注册给 LifecycleOwner 后 @OnLifecycleEvent 才可以正常使用
        if (mRootView != null && mRootView instanceof LifecycleObserver) {
            //activity ,fragment绑定自身生命周期
            ((LifecycleOwner) mRootView).getLifecycle().addObserver(this);
            if (mModel != null && mModel instanceof LifecycleObserver) {
                //activity ,fragment绑定model数据层的生命周期,当Activity销毁时,数据层感知其生命周期
                ((LifecycleOwner) mRootView).getLifecycle().addObserver((LifecycleObserver) mModel);
            }
        }
    }

这里onStart()将presenter和model作为activity/fragment的生命周期观察者,一切的根源

现在presenter就可以感知activity的生命周期变化了

TestPresenter.onCreate

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        Log.i("gw", "activity onCreate")
        mRootView.showDialogLoading()
        mModel.getWeather2("成都")
            .delay(2000, TimeUnit.MILLISECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .compose(mRootView.findActivity().bindUntilEvent(ActivityEvent.DESTROY))
            .subscribe(object : Observer<ResponseBean<WeatherBean>> {
                override fun onComplete() {
                    mRootView.hideDialogLoading()
                }

                override fun onSubscribe(d: Disposable) {
                    addDispose(d)
                }

                override fun onError(e: Throwable) {
                    e.printStackTrace()
                    mRootView.bindTest().text = "${e.message}"
                }

                override fun onNext(t: ResponseBean<WeatherBean>) {
                    Log.i("gw", "请求成功")
                    mRootView.showMessage("请求成功")
                    mRootView.bindTest().text = "${t.data.city}"
                }
            })
    }

这里在activityonCreate的时候直接请求了接口数据

然后mRootView(WeatherActivity)来刷新UI展示

效果如下

效果.gif

完整的TestPresenter

TestPresenter

/**
 * @author chenke
 * @create 2020/7/7
 * @Describe
 */
class TestPresenter : BasePresenter<TestContact.TestModel, TestContact.TestView> {

    constructor(model: TestContact.TestModel, rootView: TestContact.TestView) : super(model, rootView)

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        Log.i("gw", "activity onCreate")
        mRootView.showDialogLoading()
        mModel.getWeather2("成都")
            .delay(2000, TimeUnit.MILLISECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .compose(mRootView.findActivity().bindUntilEvent(ActivityEvent.DESTROY))
            .subscribe(object : Observer<ResponseBean<WeatherBean>> {
                override fun onComplete() {
                    mRootView.hideDialogLoading()
                }

                override fun onSubscribe(d: Disposable) {
                    addDispose(d)
                }

                override fun onError(e: Throwable) {
                    e.printStackTrace()
                    mRootView.bindTest().text = "${e.message}"
                }

                override fun onNext(t: ResponseBean<WeatherBean>) {
                    Log.i("gw", "请求成功")
                    mRootView.showMessage("请求成功")
                    mRootView.bindTest().text = "${t.data.city}"
                }
            })
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onActivityDestroy() {
        Log.i("gw", "activity finish")
        Log.i("gw", "mRootView:$mRootView")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.i("gw", "presenter销毁了")
        Log.i("gw", "mRootView:$mRootView")
    }
}

接下来,我们观察下log各个生命周期日志

onCreate的时候

onCreate.jpg

WeatherActivity点击回退finish的时候


完整生命周期.jpg

model中感知activity/fragment的生命周期

#TestModel

/**
 * @author chenke
 * @create 2020/7/7
 * @Describe
 */
class TestModel : BaseModel, TestContact.TestModel {
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onActivityDestroy() {
        Log.i("gw", "model感知activity生命周期---finish")
    }

    constructor(repositoryManager: IRepositoryManager) : super(repositoryManager)

    override fun getWeather(): Observable<ResponseBean<WeatherBean>> {
        return mRepositoryManager?.getApiHost1()?.weather()!!
    }

    override fun getWeather2(city: String): Observable<ResponseBean<WeatherBean>> {
        return mRepositoryManager?.getApiHost1()?.weather2(city)!!
    }
}

至此,简易的生命周期感知的mvp就完成了,附上demo,你可以down下来做你想要的修改

生命周期感知MVPDemo

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