对MVP模式的认识

MVP模式的概念

MVP能够有效地降低VIew复杂性,避免业务逻辑被塞进View中,使得View编程一个混乱的“大泥坑”。MVP模式会解除View与Model的耦合,同时又带来了良好的可扩展性、、可测试性,保证了系统的整洁性、灵活性。
MVP模式可以分离显示层和逻辑层,它们之间通过接口进行通信,降低耦合。理想化的MVP模式可以实现同一份逻辑代码搭配不同的显示界面,因为它们之间并不依赖于具体,而是依赖于抽象。这使得Presenter可以运用于任何实现了View逻辑接口的UI,使之具有更广泛的适用性,保证了灵活度。
MVP的模型图
MVP模式图


下面开始介绍MVP模式怎么写

  1. 首先要理解MVP模式的概念,因为要降低View与Model的耦合,所以大都是通过接口进行通信,先来看看项目的组成图。
    这里写图片描述

可以看到主要分为3个包,一是contract,这个是创建View与Presenter的基类的;二是model,就是数据实体类;三是presenter,具体的presenter处理类,逻辑处理大都是放在这个类中,前面谈到理想中的MVP模式,是可以同一个presenter类运用于不同的activity或者fragment。这里只做了一个,处理邮件的presenter。
adapter,net中放的是网络请求的类,本项目用的网络请求框架是Retrofit网络请求框架,没学过的可以借鉴Retrofit的使用

2.先来看contract是怎么写的
BaseView

//泛类基View 作用是绑定view跟presenter
public interface BaseView<T> {
    void setPresenter(T presenter);//在具体的presenter中绑定
}

MailInfoContract

/**
 * 建立共同的契约类  方法的作用一致
 * Created by prince70 on 2018/4/25.
 */

public interface MailInfoContract {

    interface View extends BaseView<Presenter> {
        void showLoading();//展示加载框

        void dismissLoading();//隐藏加载框

        void showMailInfo(MailModel.ContentBean bean);//将网络请求得到的邮件信息回调

        String uid();//网络请求需要传参  uid
    }

    interface Presenter extends BasePresenter {
        void loadMailInfo();//加载网络请求得到的邮件信息回调
    }
}

3.接下来看看model,这个应该大家都懂,平时开发都用到

public class MailModel {  
        private int total;
        private List<DataBean> data;

        public int getTotal() {
            return total;
        }

        public void setTotal(int total) {
            this.total = total;
        }

        public List<DataBean> getData() {
            return data;
        }

        public void setData(List<DataBean> data) {
            this.data = data;
        }

        public static class DataBean {      
            private int id;
            private String body;
            private String corpid;
            private String title;
            private String sendTime;
            private String founder;
            private int isdraft;
            private String foundername;
            private int accessorySum;
            private int isread;
            private int iscollect;
            private Object typeName;

            public int getId() {
                return id;
            }

            public void setId(int id) {
                this.id = id;
            }

            public String getBody() {
                return body;
            }

            public void setBody(String body) {
                this.body = body;
            }

            public String getCorpid() {
                return corpid;
            }

            public void setCorpid(String corpid) {
                this.corpid = corpid;
            }

            public String getTitle() {
                return title;
            }

            public void setTitle(String title) {
                this.title = title;
            }

            public String getSendTime() {
                return sendTime;
            }

            public void setSendTime(String sendTime) {
                this.sendTime = sendTime;
            }

            public String getFounder() {
                return founder;
            }

            public void setFounder(String founder) {
                this.founder = founder;
            }

            public int getIsdraft() {
                return isdraft;
            }

            public void setIsdraft(int isdraft) {
                this.isdraft = isdraft;
            }

            public String getFoundername() {
                return foundername;
            }

            public void setFoundername(String foundername) {
                this.foundername = foundername;
            }

            public int getAccessorySum() {
                return accessorySum;
            }

            public void setAccessorySum(int accessorySum) {
                this.accessorySum = accessorySum;
            }

            public int getIsread() {
                return isread;
            }

            public void setIsread(int isread) {
                this.isread = isread;
            }

            public int getIscollect() {
                return iscollect;
            }

            public void setIscollect(int iscollect) {
                this.iscollect = iscollect;
            }

            public Object getTypeName() {
                return typeName;
            }

            public void setTypeName(Object typeName) {
                this.typeName = typeName;
            }
        }
    }
}

这个类可以根据网络请求数据返回的json数据用GSON框架自动生成,非常便捷
* compile ‘com.squareup.retrofit2:converter-gson:2.3.0’*

3.presenter中放的就是主要的逻辑处理类MailInfoPresenter ,当然还有一个基类BasePresenter.废话不多说,直接看代码:
BasePresenter:

public interface BasePresenter {
    /**
     * 这里的start()方法就相当于约定了所有的Presenter的初始化操作都放在start()方法中;
     */
    void start();
}

MailInfoPresenter:

public class MailInfoPresenter implements MailInfoContract.Presenter {

    private static final String TAG = "MailInfoPresenter";
    private MailInfoContract.View view;

    public MailInfoPresenter(MailInfoContract.View view) {
        this.view = view;
        view.setPresenter(this);
    }

    @Override
    public void start() {
        loadMailInfo();
    }

    /**
     * 从网络上获取数据
     */
    @Override
    public void loadMailInfo() {
        String uid = view.uid();
        view.showLoading();//接口请求前显示loading

        Call<MailModel> call = MailUtil.getMails(uid);
        call.enqueue(new Callback<MailModel>() {
            @Override
            public void onResponse(@NonNull Call<MailModel> call, @NonNull Response<MailModel> response) {
                Log.e(TAG, "onResponse: " + call.request().toString());
                MailModel body = response.body();
                if (body != null) {
                    MailModel.ContentBean content = body.getContent();
                    view.showMailInfo(content);
                }
                view.dismissLoading();
            }

            @Override
            public void onFailure(@NonNull Call<MailModel> call, @NonNull Throwable t) {
                Log.e(TAG, "onFailure: " + call.request().toString());
                view.dismissLoading();
            }
        });
    }
}

可以看到所有的数据请求耗时操作都是放在MailInfoPresenter中处理,且与view建立关联,activity就主要负责显示的任务就好了

4.最后我们来看MainActivty中的代码

public class MainActivity extends AppCompatActivity implements MailInfoContract.View {
    private static final String TAG = "MainActivity";
    private ListView lv_mail;
    private List<String> mails = new ArrayList<>();

    private MailInfoContract.Presenter presenter;

    private Dialog mDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv_mail = findViewById(R.id.lv_mail);

        new MailInfoPresenter(this);
        presenter.start();
    }

    @Override
    public void setPresenter(MailInfoContract.Presenter presenter) {
        this.presenter = presenter;
    }

    @Override
    public void showLoading() {
        mDialog = new ProgressDialog(this);
        mDialog.setTitle("正在加载");
        mDialog.show();

    }

    @Override
    public void dismissLoading() {
        mDialog.dismiss();

    }

    @Override
    public void showMailInfo(MailModel.ContentBean bean) {
        if (bean != null) {
            int total = bean.getTotal();//这个数值代表请求的数据的条数,因为这个接口有上百条数据,这里只取前十条做测试
            List<MailModel.ContentBean.DataBean> data = bean.getData();
            for (int i = 0; i < 10; i++) {
                String body = data.get(i).getBody();
                mails.add(body);
            }
            Log.e(TAG, "showMailInfo: " + mails);
        }
        lv_mail.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mails));
    }

    @Override
    public String uid() {
        return "xuanhu";//传递参数
    }
}

可以看到MainActivity实现了View的接口,绑定presenter,接口的通信就实现了。至此,一个简单的MVP模式项目就完成了,源码就到github地址
如有错误,还望不吝指正

仍可能存在的问题

综上所述,MVP有很多优点,例如易于维护,易于测试,松耦合、复用性高,健壮稳定,易于扩展等。但是,由于Presenter经常性地需要执行一些耗时操作,例如,我们上述示例的请求网络数据,而Presenter持有了MainActivity的强引用,如果在请求结束之前activity被销毁了,那么由于网络请求还没有返回,导致Presenter一直持有MainActivity对象,使得MainActivity对象无法被回收,此时就发生内存泄漏。
解决办法是通过弱引用和Activity、Fragment的生命周期来解决这个问题。
详情可参考《Android源码设计模式解析与实战》,当然你能够自己实现就最好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值