从 MVP学习代码封装 (3) - 抽象 V 层生命周期模板

本系列文章集合:从 MVP学习代码封装 (1) - 综述

说在开始

看过上一篇文章的萌新们,应该都熟悉了基本的代码套路,上一篇文章中 基于 :base接口 - abs 基类 - 实现类的封装套路,这个不管放到哪里,我们写框架都基本是这个样子,这是用来搭建框架的基本架构的,但是呢,我们写自己的框架毕竟是对某一类 / 一些功能的封装,如何规划好一个框架中功能呢,我们可是要实现易阅读,易修改,易扩展的功能代码的,况且要是需要实现的功能多的话,如何做好那可是个麻烦事啊。

通过本篇呢,我想让给萌新们提供一个思路:使用模板设计模式,把单个功能抽象成一个模板接口,然后做具体逻辑实现,由框架控制层创建/持有某个功能的具体实现,既可以做到合理划分功能到单一类,在框架控制层中也很容易做某个功能的实现类替换,代码解耦了,也方便扩展替换了,而且最重要的是容易阅读了,修改起来方便很多的,不会到头来自己看不懂自己的代码了。

所以说不论是框架封装,但是最简单的胆码封装,处处都体现出设计模式的思想应用在里面,学好设计模式是我们的必须要做到的,我都认为设计模式是 java 基础中的必会技能了。不熟悉的萌新们抓紧时间啦,我也是最近才开始学习的,不足之处大家多留言啊,欢迎打脸。


话接上文

先来看看新的 UML 类图,不得不承认我画 UML 的水平实在是太 low 了,另外我画的就是个示意图,类,接口里面方法没写全,详细去看代码:


Snip20171216_4.png
  1. 模板代码抽象的都是可变的部分,留下固定的部分。这里我们需要抽象出的模板代码是针对 V 层生命周期中可以的部分,具体我们需要针对 3中 View 类型:
  • activity
  • fragment
  • view

这3种 view 类型,都有各自不同的生命周期函数,所以我们需要抽象出3个模板接口:

  • ILifecycleProxy 根接口,用来指定泛型的
  • interface IActivityLifecycleProxy extends ILifecycleProxy
  • interface IFragmentLifecycleProxy extends ILifecycleProxy
  • interface ICustomeViewLifecycleProxy extends ILifecycleProxy

具体的我们先抽象一个根接口 ILifecycleProxy ,这样方面我们使用泛型,然后用具体的类型去替换。3个具体的接口分别对应3种 view 类型

  1. 我们在 BasePersenter 这个 P 层的abs 基类中,我们添加声明周期类型的泛型,用 ILifecycleProxy 这个声明周期根接口这个类型。
public abstract class BasePersenter<V extends IBaseView, L extends ILifecycleProxy>
  1. 我思考过后呢,决定把抽象出来的可变的view 中生命周期的代码由 P 层对象来实现,在 MVP 架构中 P 层对象就是相当于最外层的控制对象的。然后根据 View 类型的不同, P 层需要实现不同的生命周期接口,鉴于生命周期接口差别的巨大和合理的设计,我在这里根据 View 类型一一对应生成多个 P 层 abs 基类来适应 View 类型。

大家注意泛型的使用,不同的 Persenter 类型在继承 BasePersenter 时,指定了不同的对应的 view 类型的生命周期接口,然后 Persenter 实现了这个生命周期接口。我们在具体的 Persenter 对象中的对应生命周期方法中写自己的逻辑即可,这里我的代码也是演示性质的,实际上是由缺漏的,大家根据实际需求去修改吧,生命周期函数太多了。

  • BaseActivityPersenter
public class BaseActivityPersenter<V extends BaseActivity> extends BasePersenter<V, IActivityLifecycleProxy> implements IActivityLifecycleProxy
  • BaseFragmentPersenter
public class BaseFragmentPersenter<V extends BaseFragment> extends BasePersenter<V, IFragmentLifecycleProxy> implements IFragmentLifecycleProxy
  • BaseCustomeViewPersenter
public class BaseCustomeViewPersenter<V extends BaseCustomeView> extends BasePersenter<V,ICustomeViewLifecycleProxy> implements ICustomeViewLifecycleProxy
  1. 在 V 层 abs 基类中,合适的地方初始化这个生命周期函数接口对象出来,然后在需要的生命周期函数中去执行这个生命周期函数模版对象的相应方法,我以Activity具个例子,更多的去看demo
public abstract class BaseActivity<V extends BaseActivity, P extends BaseActivityPersenter<V>> extends AppCompatActivity implements IBaseView {

    private P mBasePersenter;

    protected abstract P createPersenter();

    private IActivityLifecycleProxy lifecycleProxy;

    public P getPersenter() {
        return mBasePersenter;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mBasePersenter = createPersenter();
        mBasePersenter.attachView((V) this);

        lifecycleProxy = getPersenter().createlLifecycleProxy();
//        lifecycleProxy = (IActivityLifecycleProxy) Proxy.newProxyInstance(lifecycleProxy.getClass().getClassLoader(), lifecycleProxy.getClass().getInterfaces(), new NotNullnvocationHandler(lifecycleProxy));

        lifecycleProxy.onCreate(savedInstanceState);
    }

    @Override
    protected void onPause() {
        lifecycleProxy.onPause();
        super.onPause();
    }

    @Override
    protected void onResume() {
        lifecycleProxy.onResume();
        super.onResume();
    }

    @Override
    protected void onStop() {
        lifecycleProxy.onStop();
        super.onStop();
    }

    @Override
    protected void onStart() {
        lifecycleProxy.onStart();
        super.onStart();
    }

    @Override
    protected void onRestart() {
        lifecycleProxy.onStart();
        super.onRestart();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        lifecycleProxy.onNewIntent(intent);
        super.onNewIntent(intent);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        lifecycleProxy.onSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onBackPressed() {
        if (lifecycleProxy.onBackPressed()) {
            return;
        }
        super.onBackPressed();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        lifecycleProxy.onRequestPermissionsResult(requestCode, permissions, grantResults);
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        lifecycleProxy.onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onDestroy() {
        lifecycleProxy.onDestroy();

        if (mBasePersenter != null) {
            mBasePersenter.detachView();
        }
        super.onDestroy();
    }
}

这里我想说一下,我想用动态代理处理一下 IActivityLifecycleProxy 这个属性,应对这个对象意外为 null 时的情况,但是不知道为啥就是报错,报类型转换错误


最后

基本上代码的思路就是这些了,写完之后,我又掠了掠了思路,的确是对自己的代码封装水平提神很有帮助,程序员这一行真的是用大量的思考和练习时间堆积出来的。

具体来说代码很简单,虽然看起来很简单,但是在写的时候可是报了不少错啊,主要是声明周期太多了,需要考虑在合适的点初始化代码啊。

另外在思考时,我考虑 MVP 架构是更应该说是一种代码书写规范,一个 V 的就应该对应一个 P,P 在不同的 V 之间复用,这个是不切实际的,也是不符合设计规范的,不同的 V 之间实际是由大量差异的,对应 V 来说,他的 P 就是专属与自己的,这在 MVP 的设计来说就是这样的。若是不同的 V 的 P 之间有相同的代码逻辑,那也是把系相同的逻辑代码再封装成工具对象,而不是去思考如何复用 P 。所提体现在这里的是在具体的 V层对象时,传入的 V 的泛型就是自己的类型,具体例子

public class NewsActivity extends BaseActivity<NewsActivity, NewsActivityPersenter> implements INewsView

NewsActivity 中,之前 V 的泛型使用的具体的 INewsView 这个业务接口,这个业务接口是继承的 V 层根接口 IBaseView的,现在我们直接传自己就可以,因为对于 P 来说,我只需要针对一个类型 V 的就行,没机会在 V 直接复用,在实际使用中 V,可以会实现大量业务接口,这样做我们在 P 层写具体业务逻辑时会省略 V 对象在不同业务接口之间来回强转类型。

代码部分是demo 中 step2_1 这部分。


Snip20171209_48.png

最后是项目地址: BW-MVPDemo

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