Android 常见的MVP模式与封装

前言

    mvp模式大名已久,相信每个人都已经耳熟能详了。说说自己为什么要使用?
 早期mvp没有流行的同时,mvc模式就是当时的扛把子,但爱之深恨之切,每当接手别人的项目,需要改别人的代码的时候,那真是日了GOU了。activity单单是逻辑代码少则百多则千,这也是mvc的诟病之一,但是mvp就方便了许多,只要找到与其相关的m或者p改改也就差不多了。

 所以在我看来 用mvp好处就是代码解耦,结构清晰。

MVP?
与mvc最大的不同点是所有的逻辑和处理都是由Presenter 进行处理.大致的走向是现由V调用P,P在调用M.最后在由P回调V.是不是觉得很晕。花了点时间画了张图。你们理解一下
看懂的话直接上代码,废话不多说我们先来一个简单版的

这里写图片描述

需求:联网获取漫画列表数据

先来一个View层,写View接口很简单,你觉得你的activity需要什么或者P层需要什么。 就写什么

interface ComicView {
        void showList(List<ComicListInfo.EntriesBean> comicListInfos);
        void showLoading();
    }


Model层处理数据

interface ComicModel {
        void requestList(IComicCallBack iComicCallBack);
    }

Model层处理回调接口

  interface IComicCallBack {
        void ok(List<ComicListInfo.EntriesBean> comicListInfos);
    }



到这里是不是觉得,mvp要写太多接口了-v-. 所以这里可以用一个契约类把三个都写在一起

public interface ContractComic {
    interface ComicModel {
        void requestList(IComicCallBack iComicCallBack);
    }

    interface ComicView {
        void showList(List<ComicListInfo.EntriesBean> comicListInfos);
        void showLoading();
    }

    interface IComicCallBack {
        void ok(List<ComicListInfo.EntriesBean> comicListInfos);
    }
}



Model实现类

public class ComicModelImpl implements ContractComic.ComicModel {

    /**
     * 模拟请求漫画首页列表数据
     *
     * @param iComicCallBack 回调
     */
    @Override
    public void requestList(final ContractComic.IComicCallBack iComicCallBack) {
        Observable.create(new ObservableOnSubscribe<ComicListInfo>() {
            @Override
            public void subscribe(ObservableEmitter<ComicListInfo> e) throws Exception {
                Gson gson = new Gson();
                ComicListInfo comicListInfo = gson.fromJson(JsonTest.home, ComicListInfo.class);
                e.onNext(comicListInfo);
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<ComicListInfo>() {
            @Override
            public void accept(ComicListInfo comicListInfo) throws Exception {
                iComicCallBack.ok(comicListInfo.getEntries());
            }
        });
    }
}



P层

public class ComicPresenter {
    //M
    private ComicModelImpl mContractComic;
    //V
    private ContractComic.ComicView mComicView;

    public ComicPresenter() {
        mContractComic = new ComicModelImpl();
    }

    /**
     * 销毁对象,防止泄漏
     */
    public void onDestroy() {
        mComicView = null;
    }

    /**
     * 与View建立链接
     */
    public void attachView(ContractComic.ComicView view) {
        mComicView = view;
    }

    /**
     * 模拟请求数据
     */
    public void requestList() {
        //显示加载
        mComicView.showLoading();
        //调用m的方法加载数据
        mContractComic.requestList(new ContractComic.IComicCallBack() {
            @Override
            public void ok(List<ComicListInfo.EntriesBean> comicListInfos) {
                //接口回调给activity
                mComicView.showList(comicListInfos);
            }
        });
    }
}


V层,持有者P,所以逻辑都交给P处理

ppublic class ComicActivity1 extends AppCompatActivity implements ContractComic.ComicView {

    private ComicPresenter mComicPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mComicPresenter = new ComicPresenter();
        //把当前View赋予P层
        mComicPresenter.attachView(this);
        //请求数据
        mComicPresenter.requestList();
    }

    @Override
    protected void onDestroy() {
        //销毁依赖对象,防止泄漏
        mComicPresenter.onDestroy();
        super.onDestroy();
    }

    /**
     * p层回调数据
     *
     * @param comicListInfos
     */
    @Override
    public void showList(List<ComicListInfo.EntriesBean> comicListInfos) {
        Log.w("ComicActivity1", "首页数据" + comicListInfos.size());
    }

    @Override
    public void showLoading() {
        Toast.makeText(this, "加载中", Toast.LENGTH_SHORT).show();
    }
}


运行结果

这里写图片描述
一个mvp模式就完成了。当然这种只是最初的版本,要是在项目实战的话得封装一下,可以通过接口回调,多态,泛型 ,避免写重复的代码。

封装

先封装View
我们可以想象一下每个View的共性。把每个子类都会用到的方法放在这里

public interface IView {

    /**
     * 显示加载
     */
    void showLoading();

    /**
     * 隐藏加载
     */
    void hideLoading();

    /**
     * 显示信息
     */
    void showMessage(String message);
     /**
     * 设置标题
     **/
    void setToolBar(Toolbar toolBar, String title, boolean needBackButton);
    //统一消息处理
    void handleError(Exception e);
}

上面的方法几乎每个View都差不多需要。各位根据直接的项目而定

我们每个Presenter.都需要下面两个方法。我们可以抽取一下

 /**
     * 销毁对象,防止泄漏
     */
    public void onDestroy() {
        mComicView = null;
    }    /**
     * 与View建立链接
     */
    public void attachView(ContractComic.ComicView view) {
        mComicView = view;
    }
public interface IPresenter<T extends IView> {

    /**
     * 做一些初始化操作
     */
    void onStart();

    /**
     * 销毁
     */
    void onDestroy();

    /**
     * 绑定View
     */
    void attachView(T view);

    T getView();
}


这里使用到了泛型,因为要绑定attachView(T view);.类似activity,这里可以通过泛型拿到具体的绑定对象

抽取好了这边开始写实现类

BaseActivity:抽取activity的公共部分

public abstract class BaseActivity<P extends IPresenter> extends AppCompatActivity implements IView {
    //P层主导
    protected P mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            int layoutResID = getLayoutResId(savedInstanceState);
            if (layoutResID != 0) {
                setContentView(layoutResID);
                //创建P对象
                mPresenter = createPresenter();
                if (mPresenter != null) {
                    //绑定View
                    mPresenter.attachView(this);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        initData(savedInstanceState);
    }


    @Override
    protected void onDestroy() {
        //把所有的数据销毁掉
        if (mPresenter != null)
            mPresenter.onDestroy();//释放资源
        this.mPresenter = null;
        super.onDestroy();
    }
    //每个activity都需要创建Presenter
    public abstract P createPresenter();
      //每个activity都需要创建setLayoutId
    public abstract int getLayoutResId(Bundle savedInstanceState);

    public abstract void initData(Bundle savedInstanceState);

    /**
    *模拟显示加载对话框
    */
    @Override
    public void showLoading() {
        Toast.makeText(this, "加载中", Toast.LENGTH_SHORT).show();
    }
    //模拟处理统一的数据
    @Override
    public void handleError(Exception e) {
        e.printStackTrace();
        hideLoading();
        showMessage(e.getMessage());
    }

    @Override
    public void hideLoading() {
        //Log.w("11111","hideLoading");
        Toast.makeText(this, "加载结束", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showMessage(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

}




BaseFragment

public abstract class BaseFragment<P extends IPresenter> extends Fragment implements IView {
    private View parentView;
    protected FragmentActivity activity;
    protected P mPresenter;

    @LayoutRes
    public abstract int getLayoutResId();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = createPresenter();//创建presenter
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
        parentView = inflater.inflate(getLayoutResId(), container, false);
        activity = getActivity();
        return parentView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        //bind = ButterKnife.bind(this, view);
        if (mPresenter != null) {
            mPresenter.attachView(this);
        }
        finishCreateView(savedInstanceState);
    }

    /**
     * 初始化views
     *
     * @param state
     */
    public abstract void finishCreateView(Bundle state);
    public abstract P createPresenter();

    @Override
    public void onDestroy() {
        if (mPresenter != null)
            mPresenter.onDestroy();//释放资源
        this.mPresenter = null;
        super.onDestroy();
    }


    @Override
    public void onDetach() {
        super.onDetach();
        this.activity = null;
    }
    @Override
    public void showLoading() {
        Toast.makeText(activity, "加载中", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void hideLoading() {
        Toast.makeText(activity, "加载结束", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showMessage(String message) {
        Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void setToolBar(Toolbar toolBar, String title, boolean needBackButton) {

    }

    @Override
    public void handleError(Exception e) {
        hideLoading();
        showMessage(e.getMessage());
        e.printStackTrace();
    }
}



使用实例,实战
Presenter

public class ComicPresenter extends BasePresenter<ContractComic.ComicView> {
    //M
    private ComicModelImpl mContractComic;

    public ComicPresenter() {
        mContractComic = new ComicModelImpl();
    }

    /**
     * 模拟请求数据
     */
    public void requestList() {
        //显示加载
        mRootView.showLoading();
        //调用m的方法加载数据
        mContractComic.requestList(new ContractComic.IComicCallBack() {
            @Override
            public void ok(List<ComicListInfo.EntriesBean> comicListInfos) {
                //接口回调给activity
                mRootView.showList(comicListInfos);
            }
        });
    }
}



Activity

public class ComicActivity1 extends BaseActivity<ComicPresenter> implements ContractComic.ComicView {

    @Override
    public ComicPresenter createPresenter() {
        return new ComicPresenter();
    }

    @Override
    public int getLayoutResId(Bundle savedInstanceState) {
        return R.layout.activity_main;
    }

    @Override
    public void initData(Bundle savedInstanceState) {
        //请求数据
        mPresenter.requestList();
    }

    /**
     * p层回调数据
     *
     * @param comicListInfos
     */
    @Override
    public void showList(List<ComicListInfo.EntriesBean> comicListInfos) {
        Log.w("ComicActivity1", "首页数据" + comicListInfos.size());
    }

}



fragment

public class ComicFragment extends BaseFragment<ComicPresenter> implements ContractComic.ComicView {

    @Override
    public int getLayoutResId() {
        return R.layout.activity_main;
    }

    @Override
    public void finishCreateView(Bundle state) {
        mPresenter.requestList();
    }

    @Override
    public ComicPresenter createPresenter() {
        return new ComicPresenter();
    }

    @Override
    public void showList(List<ComicListInfo.EntriesBean> comicListInfos) {
        showMessage(comicListInfos.toString());
    }

}


大致上就完了。如果还不怎么 明白可以看Demo

MVPDemo

也可以我在项目的实战方面。

Comic-MTC

完结。
————————————————

转载于:https://blog.csdn.net/a8688555/article/details/79383270

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值