前言
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
也可以我在项目的实战方面。
完结。
————————————————
转载于:https://blog.csdn.net/a8688555/article/details/79383270