美文网首页
日常笔记 - MVP

日常笔记 - MVP

作者: HongGang | 来源:发表于2019-02-22 22:59 被阅读35次

1 前言

MVP模式是MVC模式在Android上的一种变体,要介绍MVP就得先介绍MVC。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。这对于开发与维护来说不太友好,耦合度大高了。把Activity的View和Controller抽离出来就变成了View和Presenter,这就是MVP模式。

2 基本实现

在实现MVP模式的过程中,会将Model、View、Presenter三者的行为(方法)抽象成接口,三者之间通过接口来相互调用,可以有效的降低耦合度

(1)Model(数据模型):Model就是数据模型,为View提供填充的数据,我们一般使用容器类来存储从网络或者本地的数据

public class IModel {
    // 定义接口方法,提供给 Presenter 来调用
    List<String> getData(boolean isNetWork);
}

public class ModelImpl implements IModel {
    @Override
    public List<String> getData(boolean isNetWork) {
        List<String> data = new ArrayList<>();
        if (!isNetWork) {
            for (int i = 0; i < 10; i++) {
                data.add("item" + i);
            }
        } else {
            // 从网络获取数据转换成 List<String> 的数据类型就可以了
        }
        return data;
    }
}

(2)Presenter(逻辑控制器):Presenter其实就是MVC中的控制器,用来将Model与View进行连接的 “房屋中介”,要当好中介就得与View和Model都有联系,即拥有其余两者的引用,来调用两者的方法

public interface IPresenter {
    // 定义 Presenter 的接口方法,提供给 View 来调用
    void start();
    void refresh();
}

public class PresenterImpl implements IPresenter {

    private IView iView;
    private IModel iModel;

    /**
     * 我们将 View 从 Presenter 的构造方法中传入,来将 Presenter 所持有的 IView 进行实例化,以便调用 View 中定义的方法
     *
     * 除此之外,我们还将 IModel 进行实例化,以便调用 ModelImpl 中实现的方法
     *
     * @param iView
     */
    public PresenterImpl(IView iView) {
        this.iView = iView;
        this.iModel = new ModelImpl();
    }

    @Override
    public void start() {
        // 此处调用 View 的初始化方法
        iView.init();
    }

    @Override
    public void refresh() {
        // 此处调用 View 的刷新方法
        iView.refresh(iModel.getData(false));
    }
}

(3)View(视图):View就是我们在Android设备中所看到的界面了,但是我们在View中不会处理一点逻辑,所有的逻辑都放在Presenter中进行调用,所以View中必须持有Presenter的对象,来调用PresenterImpl中实现的方法

public interface IView {
    // 从 View 中抽象出来的数据方法,提供给 Presenter 来调用
    void init();
    void refresh(List<String> data);
}

// 我们一般使用 Activity 或者 Fragment 来作为 IView 的实现类
public class MainActivity extends AppCompatActivity implements IView {

    private IPresenter presenter;
    private ListView lv;
    private List<String> data;
    private ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 在此处将 IPresenter 接口的对象实例化为 PresenterImpl 类的对象,以调用 PresenterImpl 中实现的方法
        presenter = new PresenterImpl(this);
        // 进行初始化
        presenter.start();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 进行刷新
        presenter.refresh();
    }

    @Override
    public void init() {
        initView();
        loadData();
    }

    public void initView() {
        lv = findViewById(R.id.list);
    }

    public void loadData() {
        data = new ArrayList<>();
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data);
        lv.setAdapter(adapter);
    }

    @Override
    public void refresh(List<String> data) {
        this.data.addAll(data);
        this.adapter.notifyDataSetChanged();
    }
}

3 进阶使用

从上面的分析可以得知,MVP将数据与视图进行分离,通过Presenter来进行逻辑控制,这样充分的进行解耦,在进行修改的时候,不会再牵一发而动全身了,优点十分明显,但是还是存在一些缺陷,比如类过多,比如内存泄漏,下面针对问题进行解决

(1)使用MVP我们会发现定义了大量的接口,并不是很好地进行管理,Google爸爸提出了契约类的方式来对定义的接口进行管理

// 具体写法就是将上面定义的接口放在 Contract 中进行统一管理,这样我们就不用再管理大量接口
public interface Contract {

    interface IModel {
        List<String> getData(boolean isNetWork);
    }

    interface IPresenter {
        void start();

        void refresh();
    }

    interface IView {
        void init();

        void refresh(List<String> data);
    }
}

(2)当我们网络数据的时候,会执行工作线程来获取数据,若是View突然关闭,但是工作线程还未执行完毕,就会导致内存泄漏,针对这种情况,可以使用软引用将View的强引用进行包装使用,除此之外,还可以将Presenter与View的生命周期进行绑定,当View销毁的同时,也将Presenter进行销毁

public interface Contract {

    interface IModel {
        List<String> getData(boolean isNetWork);
    }

    interface IPresenter {
        // 绑定
        void attachView(IView view);
        // 解绑
        void detachView();
        void start();
        void refresh();
    }

    interface IView {
        void init();
        void refresh(List<String> data);
    }
}

public class PresenterImpl implements Contract.IPresenter {

    private Contract.IModel iModel;
    // 使用软引用确保在进行垃圾回收的时候将内存进行回收
    private SoftReference<Contract.IView> softReference;

    @Override
    public void attachView(Contract.IView view) {
        this.iModel = new ModelImpl();
        this.softReference = new SoftReference<>(view);
    }

    @Override
    public void detachView() {
        if (softReference != null) {
            softReference.clear();
        }
    }

    private Contract.IView getView() {
        return softReference.get();
    }

    @Override
    public void start() {
        getView().init();
    }

    @Override
    public void refresh() {
        getView().refresh(iModel.getData(false));
    }
}

public class ModelImpl implements Contract.IModel {
    @Override
    public List<String> getData(boolean isNetWork) {
        List<String> data = new ArrayList<>();
        if (!isNetWork) {
            for (int i = 0; i < 10; i++) {
                data.add("item" + i);
            }
        } else {
            // 从网络获取数据转换成 List<String> 的数据类型就可以了
        }
        return data;
    }
}

public class MainActivity extends AppCompatActivity implements Contract.IView {

    private ListView lv;   
    private List<String> data;
    private ArrayAdapter<String> adapter;

    private Contract.IPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        presenter = new PresenterImpl();
        presenter.attachView(this);
        presenter.start();
    }

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

    @Override
    public void init() {
        initView();
        loadData();
    }

    public void initView() {
        lv = findViewById(R.id.list);
    }

    public void loadData() {
        data = new ArrayList<>();
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data);
        lv.setAdapter(adapter);
    }

    @Override
    public void refresh(List<String> data) {
        this.data.addAll(data);
        this.adapter.notifyDataSetChanged();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter.detachView();
    }
}

4 注意事项

在使用MVP模式进行开发的时候需要记得进行内存泄漏处理

相关文章

  • 日常笔记 - MVP

    1 前言 MVP模式是MVC模式在Android上的一种变体,要介绍MVP就得先介绍MVC。在MVC模式中,Act...

  • GOOGLE TODO-MVP 学习笔记

    GOOGLE TODO-MVP 学习笔记 背景(可忽略):《GOOGLE TODO-MVP 学习笔记》这篇文章主要...

  • Android MVP模式 简单入门实践

    前言 因为公司的项目用的就是MVP所以做下学习笔记了 MVP简介 MVP是Model、View、Presenter...

  • 产品经理| MVP-最小可用产品的设计之道

    转: MVP-最小可用产品的设计之道 原创:mathildaff产品经理战地笔记2018-10-01 MVP全称M...

  • 关于笔记 || 阅读《学会写作》

    一、笔记的分类 1、笔记分日常笔记和读书笔记。 2、日常笔记,记录自己日常的生活、状态、想法等; 日常笔记不一定是...

  • MVP 笔记

    公司项目代码中使用MVP,之前并没有在项目中使用过,记录一下最近一段个人写代码时学到的习惯,代码中有哪些不合理的地...

  • MVP 笔记

    MVP 与 MVC 简单介绍 实践 参考资料:Android MVP 详解(下)一步一步实现 Android 的M...

  • 231|摘抄

    1.笔记分日常笔记和读书笔记。 2.日常笔记不一定是“日记”,记录的是生活中的事情和感悟。 3.日常笔记本身也是写...

  • MVP 学习笔记

    参考资料:http://www.jianshu.com/p/9a6845b26856 1.1 MVP 的定义: M...

  • Android MVP

    Android MVP初探 Android MVP进阶 Android MVP高级 Android MVP扩展

网友评论

      本文标题:日常笔记 - MVP

      本文链接:https://www.haomeiwen.com/subject/oyoyyqtx.html