Android MVP架构浅析(续)

来源:互联网 发布:学软件发展前景好不 编辑:程序博客网 时间:2024/05/20 00:37

  继前篇博文对MVP架构做了简单解析之后遗留的问题还是挺多的,所以接下来的几篇我会慢慢重构它,尽量避免由于梯度过大而使初学者产生疑惑。关于架构设计我没有比较深刻的理解,经过几个项目的实战后,我总结了一句话:所谓设计,即在变与不变间斟酌;您是否从这句话看出了面向对象设计的理念—抽象,我觉得你是可以领悟到的,否则你就不会阅读本文了,那我们今天就先从变与不变开始吧。上篇文章中有段代码,不知你还否记得:

/** * Created by 小雨 on 2015/11/15. */public class FeedPresenter {    private FeedView mFeedView;    public FeedPresenter(FeedView feedView) {        this.mFeedView = feedView;    }    public void loadFeedList() {        this.mFeedView.showFeedList(FeedDataStoreFactory.getInstance().getFeedStoreData());    }}

  我们为View创建一个接口是毋容置疑的,但是Presenter拿到View句柄的方式是可以优化的,既然是面向接口编程,那么当前Presenter的依赖对象(View)注入形式是有问题的,已具体到功能模块,这是我们最不愿看到的。插入一段似乎不太合适的话,项目的包组织结构问题,有人喜欢按组件分,有人喜欢按功能分,不管最终以什么维度来划分,意向都是一样的,我们都希望代码结构看着整洁,那就从包结构着手吧,就像重构后的demo,我对包结构做了下调整,上层按组件分,下层按功能分,别问我为什么这么分,因为我喜欢…… 我还是稍作解释一下吧,不然有些同学肯定会打我的! 数据层(data)向表示层(presentation)提供数据,presentation并不关注data从哪里拿到的数据,DataStoreFactory负责具体执行,cache 、net or disk,这些都是data的职责,作为表示层我只负责展示就好了,不该我管的事我不管。presentation按功能模块划分包组织结构,基层构建放在根包下,其它按具体功能划分。

回到刚才Presenter依赖注入方式的问题。问题的本质就是我们把实现耦合了—多么痛的领悟… 应该依赖于抽象而不是依赖于具体! 所以先从接口抽象重构。 View的接口抽象定义:

/** * Created by 小雨 on 2015/11/15. */public interface MvpView {}

如你所见,MvpView接口并没有定义任何行为方法,它的作用就是把View从具体功能中抽象出来。

像刚才说的那样,Presenter的依赖应该被抽象出来,得到和失去本是天生一对,Presenter接口的抽象定义:

/** * Created by 小雨 on 2015/11/15. */public interface MvpPresenter<V extends MvpView> {    void attachView(V view);    void detachView(boolean retainInstance);}

Presenter接口定义好了,该如何管理View的句柄呢(何时注入? 何时销毁?),我们不可能把这些交给具体业务实现中去做吧,这样就违背了设计的初衷了Presenter持有View句柄的方式我们依然需要抽象出来,所以就有了下面这段代码:

/** * Created by 小雨 on 2015/11/15. */public abstract class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V> {    private V mView;    @Override    public void attachView(V view) {        this.mView = view;    }    protected V getView() {        return this.mView;    }    protected boolean isViewAttached() {        return this.mView != null;    }    @Override    public void detachView(boolean retainInstance) {        this.mView = null;    }}

需要注意一点的是必须在onDestroy()中调用detachView释放与view解绑。

Presenter管理View句柄的问题已经解决,那View如何持有Presenter的句柄呢,代码如下:

/** * Created by 小雨 on 2015/11/15. */public abstract class MvpBaseActivity<P extends MvpPresenter> extends AppCompatActivity implements MvpView {    protected P presenter;    protected abstract P createPresenter();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        presenter = createPresenter();        if (presenter == null) {            throw new NullPointerException("Presenter is null! Do you return null in createPresenter()?");        }        presenter.attachView(this);    }    @Override    protected void onDestroy() {        super.onDestroy();        presenter.detachView(false);    }}

MvpBaseActivity管理着View何时被注入到Presenter中,又是何时从Presenter中移除的。createPresenter()作为一个钩子延迟到子类去实现,多态的表现。

重构后的抽象基础构件已经定义好,现在时候是时候派上用场了,重构后的FeedPresenterImpl需要继承MvpBasePresenter,同时实现FeedPresenter接口即可

/** * Created by 小雨 on 2015/11/15. */public class FeedPresenterImpl extends MvpBasePresenter<FeedView> implements FeedPresenter {    public FeedPresenterImpl() {    }    @Override    public void loadFeedList() {        if (isViewAttached()) {            getView().showFeedList(FeedDataStoreFactory.getInstance().getFeedStoreData());        }    }}

因为Presenter仅以弱引用形式持有View句柄,所以每次使用前View需要判定View是否已经被销毁掉。

和FeedPresenterImpl类似,FeedActivity需要继承MvpBaseActivity,同时实现FeedView接口,具体实现代码:

/** * Created by 小雨 on 2015/11/15. */public class FeedActivity extends MvpBaseActivity<FeedPresenter> implements FeedView {    private ListView vFeedListView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        vFeedListView = (ListView) findViewById(R.id.feed_list);        init();    }    private void init() {        presenter.loadFeedList();    }    @Override    public void showFeedList(List<Feed> feedList) {        vFeedListView.setAdapter(new FeedAdapter(feedList));    }    @Override    protected FeedPresenter createPresenter() {        return new FeedPresenterImpl();    }}

至此,我们的重构告一段落了,也许你对本次重构稍有疑惑,但我相信你多看一遍就会理解。如一开始所说,本文只是重构的一环,所以你的持续关注是我前进的动力哈。

实例源码github地址:https://github.com/Tiny-Times/android-mvp2

3 0
原创粉丝点击