31.Android MVP模式

31.Android MVP模式


Android MVP介紹

先說說MVC吧,MVC(Model-View-Controller)是Java中一種非常常用的開發模式。但是在Android中,View的話可以很容易想到Activity和Fragment,但是Controller的話,我們怎麼想都還是Activity,因爲無論是Activity還是Fragment跳轉的話,都要執行startActivity所以無論怎麼想,Controller都是由Activity在兼職。

Activity身兼View和Controller的職位,導致代碼過度耦合,上千行也是常有的。

MVP(Model-View-Presenter)MVP的主要思想:

Activity或Fragment的UI邏輯對象抽象成View Interface,業務邏輯抽象成Presenter Interface,M不變。

Activity上只做簡單回調接口的數據渲染,組件的簡單操作。剩下的耗時工作(網絡請求)都交給Presenter去執行。Presenter是Model和View的橋樑,Presenter處理網絡請求後拿到的數據實例化Model,然後再將Model通過View Interface回調給View。

MVC 和 MVP 的區別: MVP中的View不能對Model直接操作。


Android MVP UML圖

mvp_uml


Android MVP實現

實體類 - Topic

public class Topic {
    /**
     * 用戶Id
     */
    public Long userId;
    /**
     * 主題Id
     */
    public Long topicId;
    /**
     * 主題內容
     */
    public String content;
}

Presenter層回調View層接口 - IMvpView

public interface IMvpView {
    /**
     * 添加成功
     * @param topic
     */
    void addSuccess(Topic topic);

    /**
     * 刪除成功
     * @param topic
     */
    void delSuccess(Topic topic);

    /**
     * 修改成功
     * @param newTopic
     */
    void modSuccess(Topic newTopic);

    /**
     * 查詢成功
     * @return
     */
    void querySuccess(List<Topic> topics);

    /**
     * 發生錯誤
     */
    void error();
}

Model層 接口 - ITopicModel

public interface ITopicModel {
    /**
     * 添加Topic
     *
     * @param topic
     */
    void add(Topic topic);

    /**
     * 刪除主題
     *
     * @param topic
     */
    void del(Topic topic);

    /**
     * 修改主題
     *
     * @param topicId
     * @param topic
     */
    void mod(Long topicId, Topic topic);

    /**
     * 查詢主題
     *
     * @return
     */
    void query();
}

Model層回調Presenter層抽象類 - TopicModelCallBack

public abstract class TopicModelCallBack {
    /**
     * 添加成功
     *
     * @param topic
     */
    public void addSuccess(Topic topic) {
    }

    /**
     * 刪除成功
     *
     * @param topic
     */
    public void delSuccess(Topic topic) {
    }

    /**
     * 修改成功
     *
     * @param newTopic
     */
    public void modSuccess(Topic newTopic) {
    }

    /**
     * 查詢成功
     *
     * @return
     */
    public void querySuccess(List<Topic> topics) {
    }

    /**
     * 發生錯誤
     */
    public abstract void error();
}

Model 實現類 - TopicModel

public class TopicModel implements ITopicModel {

    private TopicModelCallBack callBack;

    public TopicModel(TopicModelCallBack callBack) {
        this.callBack = callBack;
    }

    /**
     * 添加Topic
     *
     * @param topic
     */
    @Override
    public void add(Topic topic) {
        // TODO ...網絡請求後...

        // TODO 返回數據 這裏默認爲返回原數據
        this.callBack.addSuccess(topic);
    }

    /**
     * 刪除主題
     *
     * @param topic
     */
    @Override
    public void del(Topic topic) {
        // TODO ...網絡請求後...

        // TODO 返回數據 這裏默認爲返回原數據
        this.callBack.delSuccess(topic);
    }

    /**
     * 修改主題
     *
     * @param topicId
     * @param topic
     */
    @Override
    public void mod(Long topicId, Topic topic) {
        // TODO ...網絡請求後...

        // TODO 返回數據 這裏默認爲返回原數據
        this.callBack.modSuccess(topic);
    }

    /**
     * 查詢主題
     *
     * @return
     */
    @Override
    public void query() {
        // TODO ...網絡請求後...

        // TODO 返回數據
        Topic topic = new Topic();
        topic.userId = 267L;
        topic.topicId = 1267L;
        topic.content = "Save you from anything";
        List<Topic> list = new LinkedList<Topic>();
        list.add(topic);
        this.callBack.querySuccess(list);
    }
}

Presenter層 - MvpPresenter

public class MvpPresenter {
    private IMvpView iView;
    private ITopicModel model;

    public MvpPresenter(IMvpView iView) {
        this.iView = iView;
        this.model = new TopicModel(new TopicModelCallBack() {
            /**
             * 添加成功
             *
             * @param topic
             */
            @Override
            public void addSuccess(Topic topic) {
                MvpPresenter.this.iView.addSuccess(topic);
            }

            /**
             * 刪除成功
             *
             * @param topic
             */
            @Override
            public void delSuccess(Topic topic) {
                MvpPresenter.this.iView.delSuccess(topic);
            }

            /**
             * 修改成功
             *
             * @param newTopic
             */
            @Override
            public void modSuccess(Topic newTopic) {
                MvpPresenter.this.iView.modSuccess(newTopic);
            }

            /**
             * 查詢成功
             *
             * @param topics
             * @return
             */
            @Override
            public void querySuccess(List<Topic> topics) {
                MvpPresenter.this.iView.querySuccess(topics);
            }

            /**
             * 發生錯誤
             */
            @Override
            public void error() {
                MvpPresenter.this.iView.error();
            }
        });
    }

    /**
     * 添加主題
     *
     * @param topic
     */
    public void addTopic(Topic topic) {
        this.model.add(topic);
    }

    /**
     * 刪除主題
     *
     * @param topic
     */
    public void delTopic(Topic topic) {
        this.model.del(topic);
    }

    /**
     * 修改主題
     *
     * @param topic
     */
    public void modTopic(Topic topic) {
        this.model.mod(topic.topicId, topic);
    }

    /**
     * 查詢主題
     */
    public void queryTopic() {
        this.model.query();
    }


}

Activity

public class MvpActivity extends AppCompatActivity implements IMvpView {

    private TextView addTV;
    private TextView delTV;
    private TextView modTV;
    private TextView queryTV;

    private MvpPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvp);

        this.addTV = (TextView) this.findViewById(R.id.add_tv);
        this.delTV = (TextView) this.findViewById(R.id.del_tv);
        this.modTV = (TextView) this.findViewById(R.id.mod_tv);
        this.queryTV = (TextView) this.findViewById(R.id.query_tv);

        this.presenter = new MvpPresenter(this);

        Topic topic = new Topic();
        topic.userId = 267L;
        topic.topicId = 1267L;
        topic.content = "Save you from anything";

        this.presenter.addTopic(topic);
        this.presenter.delTopic(topic);
        this.presenter.modTopic(topic);
        this.presenter.queryTopic();

    }

    /**
     * 添加成功
     *
     * @param topic
     */
    @Override
    public void addSuccess(Topic topic) {
        Log.i("MvpActivity", topic.content);
        this.addTV.setText("Add:"+topic.content);
    }

    /**
     * 刪除成功
     *
     * @param topic
     */
    @Override
    public void delSuccess(Topic topic) {
        Log.i("MvpActivity",topic.content);
        this.delTV.setText("Del:"+topic.content);
    }

    /**
     * 修改成功
     *
     * @param newTopic
     */
    @Override
    public void modSuccess(Topic newTopic) {
        Log.i("MvpActivity", newTopic.content);
        this.modTV.setText("Mod:" + newTopic.content);
    }

    /**
     * 發生錯誤
     */
    @Override
    public void error() {

    }

    /**
     * 查詢成功
     *
     * @param list
     * @return
     */
    @Override
    public void querySuccess(List<Topic> list) {
        Topic topic = list.get(0);
        Log.i("MvpActivity",topic.content);
        this.queryTV.setText("Query:"+topic.content);
    }
}

Android MVP項目結構

mvp_project


Android MVP作用

  • 在Android上,分離了View和Controller,大大降低了耦合度。

  • Activity只處理簡單的事情,代碼乾淨。

  • Presenter被抽象出來可以有多種具體的實現,方便進行單元測試。

  • Presenter和View都獨立出來了,不互相耦合,提升了各自功能的特點和可讀性(比如Presenter就是幹這個的,View是幹這個的,很容易看出來)。

  • 網絡的耗時任務內,可能Activity的引用還被耗時任務引用着,這樣會造成內存泄露,如果業務邏輯交給Presenter,可以在onDestory的時候讓Presenter分離耗時任務和Activity的引用。


代碼下載

Mvp4Android Demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章