我的MVP自学笔记1:MVP简介与实践

1、前沿

时隔2年我又重新回来审视了我这篇当时入门的文章,也正如文下读者所说当时确实是在MVP的Activity中开辟了线程的,且不说在页面退出时线程仍然未结束且持有activity会造成内存泄漏,再有这完全违背了MVP的设计思想,我提一点在MVP中Activity仅仅作为View提供UI操作(2020-07-30)。

2、简介

这是一篇基础的mvp案例的demo,也是提供一个记录的作用,由于是一个小白,烦请写的不当的地方能指出来,共同进步,谢谢。mvp的概念啥的我就不再累赘了,网上资源很多,我以为 mvp能通过增加类的方式让程序结构清晰,活动充当View,仅仅就是用来显示数据的,Model层就是各种数据Bean,而核心的P层起承上启下的作用,View层通过调用P层方法,让P层去做复杂的逻辑处理,诸如网络请求和数据库读取,P层将数据处理完了之后让View层去更新操作。当活动或者Fragment结束时,解除与P层的绑定,那么即便此时P层有耗时操作,也不会影响活动的正常退出,那么也就规避了内存泄漏带来的问题。

如上简介当时写的比较笼统,这里我也不删除了,我需要做一些补充(2020-07-30)

在说明MVP之前我想得对MVC得有个充分的了解

MVC  vs MVP

MVP相较MVC最大的一个特点就是 M与V完全解耦,M与V的交互完全通过P层来中介传递

MVC

在Android中

  • M 包括网络请求、数据库操作、数据Bean
  • V  对应xml
  • C  对应Activity  当用户操作数据,view得到响应,通过C来执行M层数据变化;数据改变通过C来改变UI的显示

MVP

  • M 包括网络请求、数据库操作、数据Bean
  • V 对应Activity以及一些列的View
  • P M与V的桥梁,P作为中间人协调M与V的工作

小结

如上可以看出,

在Android中Activity在MVC和MVP中承担的责任不同,在MVC中承担着C的职责,而在MVP中承担着V的职责;

在MVP中M与V完全解耦,我们把M与V更好的分离也更符合Android对于UI刷新的思想定义,我们需要在子线程中做网络请求而我们又需要在主线程中刷新UI;

3、案例

案例实现的是,点击图像然后更换图片进行提交,处理成功后显示的过程。

V层基类

// 因为不可避免的涉及到进度条,故而有必要抽离出来
public interface BaseView {
    void showLoadingDialog();
    void hideLoadingDialog();
}

P层基类

因为P层持有了活动的引用了,那么当活动主动结束时,可通过detachView解除V与P的绑定,那么活动即可正常的被回收,可以规避内存泄漏。

/**
 * @author zxl
 * @date 2018/4/17
 *
 * 关于Reference解释: 一个接口即引用
 *     共计四个实现类: SoftReference;WeakReference;PhantomReference;FinalizerReference
 *
 *     SoftReference: 软引用,引用的对象发生GC时,假若内存比较紧张,就会释放其所占的内存,充实的话便不会释放
 *     WeakReference: 弱引用,所引用的对象发生GC时,不管内存如何都会释放其所占用的内存
 *     PhantomReference: /['fæntəm]/ 虚引用,无法引用一个对象
 *
 */

public class BasePresenter<V extends BaseView> {
    public BaseActivity mContext;

    public BasePresenter(BaseActivity context) {
        mContext = context;
    }

    protected Reference<V> mViewRef;
    public void attachView(V view){
        this.mViewRef = new WeakReference<>(view);
    }

    public void detachView(){
        if (mViewRef != null){
            mViewRef.clear();
            mViewRef = null;
        }
    }

    public V getView(){
        return mViewRef !=null?mViewRef.get():null;
    }
}

BaseActivity

public abstract class BaseActivity<V extends BaseView,T extends BasePresenter<V>> extends SupportActivity {
    protected T mPresenter;
    protected Context mContext;
    @SuppressWarnings("SpellCheckingInspection")
    private Unbinder mUnbinder = null;

    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        doBeforeSetContentView();
        mContext = this;
        init();
        mPresenter = createPresenter();
        if (mPresenter != null) {
            //因为之后所有的子类都要实现对应的View接口
            mPresenter.attachView((V) this);
        }
        setContentView(provideContentViewId());
        mUnbinder = ButterKnife.bind(this);
        initView(savedInstanceState);
        initData();
        initListener();
    }

    private void doBeforeSetContentView() {

    }

    //在setContentView()调用之前调用,可以设置WindowFeature(如:this.requestWindowFeature(Window.FEATURE_NO_TITLE);)
    protected abstract void init();

    //得到当前界面的布局文件id(由子类实现)
    protected abstract int provideContentViewId();

    //用于创建Presenter和判断是否使用MVP模式(由子类实现)
    protected abstract T createPresenter();

    protected abstract void initView(Bundle savedInstanceState);

    protected abstract void initData();

    protected abstract void initListener();


    public void jumpToActivity(Intent intent) {
        startActivity(intent);
    }

    public void jumpToActivity(Class activity) {
        Intent intent = new Intent(this, activity);
        startActivity(intent);
    }

    /**
     *  含有bundle跳转
     *  */
    public void jumpToActivity(Class cls,Bundle bundle){
        Intent intent = new Intent(this,cls);
        if (bundle != null){
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }

    public void jumpToActivityForResult(Class cls,int requestCode){
        jumpToActivityForResult(cls,null,requestCode);
    }

    public void jumpToActivityForResult(Class cls,Bundle bundle,int requestCode){
        Intent intent = new Intent(this,cls);
        if (bundle != null){
            intent.putExtras(bundle);
        }
        startActivityForResult(intent,requestCode);
    }

    public void jumpToActivityAndClearTask(Class activity) {
        Intent intent = new Intent(this, activity);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
        finish();
    }
    
   // 这里可以自行去封装
   public void showLoadingDialog() {
        PerfectLoader.showLoading(mContext, LoaderStyle.BallScaleRippleMultipleIndicator);
    }

    public void hideLoadingDialog() {
        PerfectLoader.stopLoading();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        isConfigChange=true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.detachView();
        }
        if (mUnbinder != null) {
            mUnbinder.unbind();
        }

    }
}

具体View层

/**
 * @author crazyZhangxl on 2018/9/27.
 * Describe: 个人中心的V层
 */
public interface IPersonalAtView extends BaseView {

    void postHeadSuccess(String imagePath);

    void postHeadFailure(String error);
}

具体的P层


/**
 * @author crazyZhangxl on 2018/9/27.
 * Describe: 个人中心的P层
 */
public class PersonalAtPresenter extends BasePresenter<IPersonalAtView> {

    public PersonalAtPresenter(BaseActivity context) {
        super(context);
    }


    @SuppressLint("CheckResult")
    public void doPostHeadImage(String imagePath){
        getView().showLoadingDialog();
        ApiRetrofit.getInstance().postHeadImage(new File(imagePath))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(baseResponse -> {
                    getView().hideLoadingDialog();
                    if (baseResponse.getCode() == 1){
                        getView().postHeadSuccess(baseResponse.getData().getImage());
                    }else {
                       getView().postHeadFailure(baseResponse.getMsg());
                    }
                }, throwable -> {
                    getView().hideLoadingDialog();
                    getView().postHeadFailure(throwable.getLocalizedMessage());
                });
    }
}

Activity

/**
 * @author zxl on 2018/09/26.
 * Describe: 个人中心活动,活动中不能有耗时操作
 */
public class PersonalActivity extends BaseActivity<IPersonalAtView,PersonalAtPresenter> implements IPersonalAtView {
    @BindView(R.id.img_bg)
    ImageView imgBg;
    @BindView(R.id.wave_view)
    WaveView waveView;
    @BindView(R.id.img_avater)
    CircleImageView imgAvater;
    @BindView(R.id.tv_name)
    TextView tvName;
    @BindView(R.id.ivToolbarNavigation)
    ImageView ivToolbarNavigation;
    public List<LocalMedia> mSingleSelectList = new ArrayList<>();
    @BindView(R.id.stv_about_cloud)
    SuperTextView stvAboutCloud;
    @BindView(R.id.stv_logout)
    SuperTextView stvLogout;
    private View mExitView;
    private CustomDialog mExitDialog;
    @Override
    protected void init() {

    }

    @Override
    protected int provideContentViewId() {
        return R.layout.activity_personal;
    }

    @Override
    protected PersonalAtPresenter createPresenter() {
        return new PersonalAtPresenter(this);
    }

    @Override
    protected void initView(Bundle savedInstanceState) {
        
    }

    @Override
    protected void initData() {
        
    }

    @Override
    protected void initListener() {
        // 设置单张图片的点击事件
        imgAvater.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PictureSHelper.getInstance().
                        chooseSinglePictureEvent(PersonalActivity.this,mSingleSelectList,PictureConfig.SINGLE);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {
                case PictureConfig.SINGLE:
                    mSingleSelectList = PictureSelector.obtainMultipleResult(data);
                    // 执行P层的上传图片
                    mPresenter.doPostHeadImage(mSingleSelectList.get(0).getPath());
                    break;
                default:
                    break;
            }
        }
    }


    /**
     * 上传头像
     * @param imagePath
     */
    @Override
    public void postHeadSuccess(String imagePath) {
        UserCache.setUserImage(imagePath);
        mSingleSelectList.clear();
        GlideLoaderUtils.display(this,imgAvater,imagePath);
    }

    @Override
    public void postHeadFailure(String error) {
        UIUtils.showToast(error);
    }

}

好了,以上就是一个完整的mvp的小例子,由于是项目代码故而没法把源码给齐。后面也会考虑将以上的完善。前辈提示的是,活动中千万别做耗时操作,那么这和mvc就没区别了,要充分利用mvp的优势。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值