Android-MVP Demo
说在前面
引用Rocko说过的一段话
MVP作为一种MVC的演化版本在Android开发中受到了越来越多的关注,但在项目开发中选择一种这样的软件设计模式需保持慎重心态,一旦确定使用MVP作为你App的开发模式那么你就最好坚持做下去,如果在使用MVP模式开发过程中发现问题而且坑越来越大,这时你想用MVC等来重新设计的话基本上就等于推倒重来了。要知道在Android上MVP在现在为止并没有统一的标准或者框架,不像SSH这三个成熟稳重强而有力的三剑客支持推动着Java EE的开发,所以在运用MVP时一定要做好自己的理解,并且尽量预知自己App各模块的需求以便提前做好充分的设计工作。
其实关于MVP的文章已经很多了,我觉得我再去说一些理论性的东西显得有点“老套”,所以我直接上一个小的项目(知乎日报)。关于理论知识这里推荐两篇文章,我也是按照这个来自己学习的。仔细想一想,多写一写。
关于知乎日报的实现
我的MVP学的还不是很到位,所以有出错的地方请各位指正
MVP实现的是View和Model的解耦,View中只需要实现接口来接收数据显示界面即可
所以,当我们开始写一个界面的时候,我们就应该想这个界面需要“哪些数据”?我们就根据这个想法来定义接口,至于处理数据/提供数据就交给Presenter去处理。
知乎日报大家都熟悉,我这里只写了一个首页,应该说很简单。
如图:

然后看一下工程的目录,如下

model就是我们的数据了,presenter就是我们的中间层,来处理数据,至于ui就更不用说了,我们的activity、fragment等都放在这。
首先我们要构思一下,这个页面需要什么?
- banner
- ListView的数据
- 拉倒最后加载更多的数据
- 加载失败的回调
根据这几个我们就可以定义出来一个view的接口IZhiHuFgView
,接口如下:
public interface IZhiHuFgView {
/**
* 加载的的数据
*/
void setStories(List<Stories> stories);
/**
* 设置banner的View
*/
void setBanner(View bannerView);
/**
* 出错
*/
void onError();
}
然后我们的ZhiHuFragment
来实现这个接口,实现这些方法就可以来添加数据了
public class ZhiHuFragment extends Fragment implements IZhiHuFgView, AbsListView.OnScrollListener, SwipeRefreshLayout.OnRefreshListener {
@Bind(R.id.stories_list)
ListView storiesList;
@Bind(R.id.refresh_view)
SwipeRefreshLayout refreshView;
/**
* 持有presenter的对象来处理数据
*/
private IZhiHuFgPresenter zhiHuFgPresenter;
private List<Stories> stories;
private StoriesAdapter storiesAdapter;
private boolean isRequest = false;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = LayoutInflater
.from(getContext())
.inflate(R.layout.fragment_zhihu, container, false);
ButterKnife.bind(this, view);
init();
return view;
}
/**
* 初始化一些view
*/
private void init() {
zhiHuFgPresenter = new ZhiHuFgPresenter(getActivity(), this);
storiesAdapter = new StoriesAdapter(getContext());
storiesList.setAdapter(storiesAdapter);
stories = new ArrayList<>();
refreshView.setColorSchemeColors(
getActivity().getResources().getColor(R.color.colorPrimary));
refreshView.post(new Runnable() {
@Override
public void run() {
refreshView.setRefreshing(true);
}
});
refreshView.setOnRefreshListener(this);
storiesList.setOnScrollListener(this);
zhiHuFgPresenter.getZhiHuStories();
}
/**
* 设置加载的数据
*/
@Override
public void setStories(List<Stories> stories) {
isRequest = false;
this.stories.addAll(stories);
storiesAdapter.setData(this.stories);
refreshView.post(new Runnable() {
@Override
public void run() {
refreshView.setRefreshing(false);
}
});
}
/**
* 设置banner
*/
@Override
public void setBanner(View bannerView) {
storiesList.addHeaderView(bannerView);
}
/**
* 出错
*/
@Override
public void onError() {
Toast.makeText(getContext(), "error", Toast.LENGTH_SHORT).show();
}
/**
* 加载更多滑动监听
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE
&& view.getLastVisiblePosition() == (view.getCount() - 1) && !isRequest) {
isRequest = true;
zhiHuFgPresenter.getBeforeStories();
}
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
/**
* 刷新
*/
@Override
public void onRefresh() {
stories.clear();
zhiHuFgPresenter.getZhiHuStories();
}
@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
}
可以清楚的看到,我们的view层只是用来展示数据,调理是不是清晰了很多,剩下的就是用presenter这个中间层来处理数据回调给view层了,代码很简单,就不贴了,有需要的可以移步GitHub查看详细代码
自我理解
MVP最大的好处就是View和Model的解耦,方便单元测试等。但是代码量很多,会创建出很多的View层接口。
我觉得写MVP的一个难点就是在于抽离,要思考这个页面需要什么,然后设计成接口
文笔不佳,抱歉了各位
最后
爱生活,爱小丽,爱Android