Android MVP 开发epc模式的优缺点有哪些优缺点

推荐这篇日记的豆列
&&&&&&&&&&&&
&(1人关注)&nbsp&#8250&nbsp&nbsp&#8250&nbsp
浅谈Andorid开发中的MVP模式
导语:最近公众号后台经常收到一些消息,说能不能讲一些开发模式,经过思考后,我决定讲一讲MVP模式。希望对大家能够有所帮助。并写了一个简单的小demo。背景看到MVP,大家肯定会想什么是MVP呢?这个我可以肯定的告诉大家MVP(Most Valuable Player)是最有价值球员的意思,这当然是开玩笑了。之所以会出现MVP这种架构模式,是因为我相信大家在开发App时,肯定会发现,Activity的负担非常重,既要初始化控件,又要写一些逻辑操作的展示等等,有时候很多Activity中的代码都充当了Controller和Model的角色,所以你会发现Activity违背单一职责原则,负担过重。所以,就出现了这么一种架构模式,叫MVP,并不是最有价值球员哦。什么是MVP架构MVP就是Model-View-Presenter,MVP是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,及View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。用流程图的方式解释就更清楚了:MVP和MVC的区别,及MVP是如何解决MVC的问题?MVP架构:View: 对应于Activity,负责View的绘制以及与用户交互Model: 依然是业务逻辑和实体模型Presenter: 负责完成View于Model间的交互View不直接与Model交互,而是通过与Presenter交互来与Model间接交互。Presenter与View的交互是通过接口来进行的。通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。MVC架构:View:对应于布局文件Model:业务逻辑和实体模型Controllor:对应于ActivityView可以与Model直接交互。Controller是基于行为的,并且可以被多个View共享。可以负责决定显示哪个View。总结解释一下就是说:从MVC到MVP的一个转变,就是减少了Activity的职责,减轻了它的负担,简化了Activity中的代码和一些操作,将逻辑代码提取到了Presenter中进行处理,降低了其耦合度。进一步的解释:在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,即重用! 不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试--而不需要使用自动化的测试工具。 我们甚至可以在Model和View都没有完成时候,就可以通过编写Mock Object(即实现了Model和View的接口,但没有具体的内容的)来测试Presenter的逻辑。 在MVP里,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层。因此就有人提出了Presenter First的设计模式,就是根据User Story来首先设计和开发Presenter。在这个过程中,View是很简单的,能够把信息显示清楚就可以了。在后面,根据需要再随便更改View,而对Presenter没有任何的影响了。 如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,就可以在View和Presenter之间放置一个Adapter。由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。 在MVP模式里,View只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model--这就是与MVC很大的不同之处。MVP的优点1.降低耦合度,隐藏数据,Activity中代码更简洁2.模块职责划分明显3.方便测试驱动开发4.代码复用度较高5.代码灵活性MVP架构模式实例这个实例是根据用户id获取用户信息并展示的一个过程,其中获取用户信息用了一个线程进行了模拟获取。希望大家能够看懂,并对大家有所帮助。我们先看一下MVP目录结构图1、Model层首先是一个javabean User实体类package net.loonggg.mvpdemo.public class User { & & & &private S & & & &private S & & & &private S & & & &private S & & & &public String getName() { & & & & & & & &return
& &} & & & & & &public void setName(String name) { & & & & & & & &this.name =
& &} & & & &public String getId() { & & & & & & & &return
& &} & & & &public void setId(String id) { & & & & & & & &this.id =
& &} & & & &public String getSex() { & & & & & & & &return
& &} & & & &public void setSex(String sex) { & & & & & & & &this.sex =
& &} & & & &public String getAge() { & & & & & & & &return
& &} & & & &public void setAge(String age) { & & & & & & & &this.age =
}Model层抽象接口实现:package net.loonggg.mvpdemo.import net.loonggg.mvpdemo.bean.Upublic class GetUserInfo implements IGetUser { & & & &@Override
& &public void getUserInfo(final int id, final OnUserInfoListener listener) { & & & &
& & & &new Thread() { & & & & & & & & & & & &@Override
& & & & & &public void run() { & & & & & & & & & & & & & & & &try {
& & & & & & & & & &Thread.sleep(2000);
& & & & & & & &} catch (InterruptedException e) {
& & & & & & & & & &e.printStackTrace();
& & & & & & & &} & & & & & & & &
& & & & & & & &if (id == 1) {
& & & & & & & & & &User user = new User();
& & & & & & & & & &user.setName(&非著名程序员&);
& & & & & & & & & &user.setAge(&26&);
& & & & & & & & & &user.setSex(&男&);
& & & & & & & & & &user.setId(&1&);
& & & & & & & & & &listener.getUserInfoSuccess(user);
& & & & & & & &} else {
& & & & & & & & & &listener.getUserInfoFailed();
& & & & & & & &}
& & & & & &}
& & & &}.start();
}Model层抽象接口package net.loonggg.mvpdemo.public interface IGetUser { & & & &public void getUserInfo(int id, OnUserInfoListener listener);
}package net.loonggg.mvpdemo.import net.loonggg.mvpdemo.bean.Upublic interface OnUserInfoListener { & & & &void getUserInfoSuccess(User user); &
& && & &void getUserInfoFailed();
}2、View层我们都知道Presenter与View交互是通过接口,所以我们需要定义一个IShowUserView的接口,这个接口封装的方法基本上都跟视图展示有关。package net.loonggg.mvpdemo.import net.loonggg.mvpdemo.bean.Upublic interface IShowUserView { & & & &void showLoading(); & & & &void hideLoading(); & & & &void toMainActivity(User user); & & & &void showFailedError();
}3、Presenter层Presenter是Model和View之间交互的桥梁,里面有一些业务逻辑的操作。public class UserInfoPresenter { & & & &private IGetUser iGetU & & & &private IShowUserView iShowUserV & & & &private Handler mHandler = new Handler(); & & & &public UserInfoPresenter(IShowUserView iShowUserView) { & & & & & & & &this.iShowUserView = iShowUserV & & & & & & & &this.iGetUser = new GetUserInfo();
& &} & & & & & &public void getUserInfoToShow(int id) {
& & & &iShowUserView.showLoading();
& & & &iGetUser.getUserInfo(id, new OnUserInfoListener() { & & & & & &@Override
& & & & & &public void getUserInfoSuccess(final User user) { & & & & & & & &
& & & & & & & &mHandler.post(new Runnable() { & & & & & & & & & &@Override
& & & & & & & & & &public void run() {
& & & & & & & & & & & &iShowUserView.toMainActivity(user);
& & & & & & & & & & & &iShowUserView.hideLoading();
& & & & & & & & & &}
& & & & & & & &});
& & & & & &} & & & & & &@Override
& & & & & &public void getUserInfoFailed() {
& & & & & & & &mHandler.post(new Runnable() { & & & & & & & & & &@Override
& & & & & & & & & &public void run() {
& & & & & & & & & & & &iShowUserView.showFailedError();
& & & & & & & & & & & &iShowUserView.hideLoading();
& & & & & & & & & &}
& & & & & & & &});
& & & & & &}
& & & &});
}4、Activity中的调用public class MainActivity extends Activity implements IShowUserView { & & & &private B & & & &private TextView name_tv, age_tv, sex_ & & & &private ProgressDialog pd = null; & & & & & &private UserInfoPresenter userInfoP & & & &@Override
& &protected void onCreate(Bundle savedInstanceState) { & & & & & & & &super.onCreate(savedInstanceState);
& & & &setContentView(R.layout.activity_main);
& & & &userInfoPresenter = new UserInfoPresenter(this);
& & & &btn = (Button) findViewById(R.id.btn);
& & & &name_tv = (TextView) findViewById(R.id.name_tv);
& & & &age_tv = (TextView) findViewById(R.id.age_tv);
& & & &sex_tv = (TextView) findViewById(R.id.sex_tv);
& & & &pd = new ProgressDialog(this);
& & & &pd.setMessage(&正在加载……&);
& & & &btn.setOnClickListener(new View.OnClickListener() { & & & & & &@Override
& & & & & &public void onClick(View v) {
& & & & & & & &userInfoPresenter.getUserInfoToShow(1);
& & & & & &}
& & & &});
& &} & & & & & &@Override
& &public void showLoading() {
& & & &pd.show();
& &} & & & & & &@Override
& &public void hideLoading() {
& & & &pd.cancel();
& & & &@Override
& &public void toMainActivity(User user) {
& & & &name_tv.setText(user.getName());
& & & &age_tv.setText(user.getAge());
& & & &sex_tv.setText(user.getSex());
& &} & & & & & &@Override
& &public void showFailedError() {
& & & &Toast.makeText(this, &获取信息有误&, Toast.LENGTH_SHORT).show();
}结语:看完实例代码,有点感觉了吧?俗话说好记性不如烂笔头,看不如写,试着自己去写一个,领会一下其中的精神,相信你会豁然开朗。当然有人说这么做,是不是又多了一层,感觉又麻烦了,是吗?降低了耦合度,提取了代码,并增加了复用,代码更简洁,其实好处还是很多的。移动开发者的聚集地,公众号“非著名程序员”,每天一篇原创技术分享和移动互联网知识分享,微信公众号:smart_android  以前在写项目的时候,没有过多考虑架构模式的问题,因为之前一直做J2EE开发,而J2EE都是采用MVC模式进行开发的,所以在搭建公司项目的时候,也是使用类似MVC的架构(严格来讲,之前的项目还算不上MVC模式,只是简单将网络请求与界面分离,然后通过Handle通知更新界面)。这种写法,在后面随着项目越来越大,Activty或者Fragment中代码也会越来越多,导致项目的维护变的越来越复杂。所以需要另外一种架构模式来解决这个问题,在网上浏览了一圈,发现适合Android开发的架构模式非MVP莫属了。
  网上一搜,讲MVP模式的文章比比皆是。但是大多都是讲理论,稍微好点的会附带一个简单的登录的demo。一个简单的demo很难让初次接触MVP模式的人掌握它的使用。所以我决定写一个稍微复杂一点的新闻客户端SimpleNews(当然只是相对登录的demo)来展示MVP在具体项目中的使用。另外SimpleNews还使用了Material Design,也是学习Material Design的一个好Demo。
  好了,切入正文吧。先讲一下MVP的概念。
  MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别代表项目中3个不同的模块。
  模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等;
  视图(View):负责界面数据的展示,与用户进行交互;
  主持人(Presenter):相当于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。
  如下图所示,View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。
  这样分层的好处就是大大减少了Model与View层之间的耦合度。一方面可以使得View层和Model层单独开发与测试,互不依赖。另一方面Model层可以封装复用,可以极大的减少代码量。当然,MVP还有其他的一些优点,这里不再赘述。下面看下MVP模式在具体项目中的使用。
MVP模式在项目中的使用
  View层新闻展示模块的是组件是Fragment,里面有一个RecyclerView、SwipeRefreshLayout。布局代码如下:
&?xml version="1.0" encoding="utf-8"?&
&android.support.v4.widget.SwipeRefreshLayout
xmlns:android="/apk/res/android"
xmlns:app="/apk/res-auto"
android:id="@+id/swipe_refresh_widget"
android:layout_width="match_parent"
android:layout_height="match_parent"&
&android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:paddingTop="@dimen/card_margin"&
&/android.support.v7.widget.RecyclerView&
&/android.support.v4.widget.SwipeRefreshLayout&
  新闻列表模块主要是展示从网络获取的新闻列表信息,View层的接口大概需要如下方法:
  (1)加载数据的过程中需要提示&正在加载&的反馈信息给用户
  (2)加载成功后,将加载得到的数据填充到RecyclerView展示给用户
  (3)加载成功后,需要将&正在加载&反馈信息取消掉
  (4)若加载数据失败,如无网络连接,则需要给用户提示信息
  根据上面描述,我们将View层的接口定义如下,分别对应上面四个方法:
public interface NewsView {
void showProgress();
void addNews(List&NewsBean& newsList);
void hideProgress();
void showLoadFailMsg();
  在新闻列表Fragment中实现上述接口:
package com.lauren.simplenews.news.
import android.content.I
import android.os.B
import android.support.annotation.N
import android.support.design.widget.S
import android.support.v4.app.ActivityC
import android.support.v4.app.ActivityOptionsC
import android.support.v4.app.F
import android.support.v4.widget.SwipeRefreshL
import android.support.v7.widget.DefaultItemA
import android.support.v7.widget.LinearLayoutM
import android.support.v7.widget.RecyclerV
import android.view.LayoutI
import android.view.V
import android.view.ViewG
import com.lauren.simplenews.R;
import com.lauren.simplenews.beans.NewsB
import com.mons.U
import com.lauren.simplenews.news.NewsA
import com.lauren.simplenews.news.presenter.NewsP
import com.lauren.simplenews.news.presenter.NewsPresenterI
import com.lauren.simplenews.news.view.NewsV
import com.lauren.simplenews.utils.LogU
import java.util.ArrayL
import java.util.L
* Description : 新闻Fragment
* Author : lauren
: 15/12/13
public class NewsListFragment extends Fragment implements NewsView, SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "NewsListFragment";
private SwipeRefreshLayout mSwipeRefreshW
private RecyclerView mRecyclerV
private LinearLayoutManager mLayoutM
private NewsAdapter mA
private List&NewsBean& mD
private NewsPresenter mNewsP
private int mType = NewsFragment.NEWS_TYPE_TOP;
private int pageIndex = 0;
public static NewsListFragment newInstance(int type) {
Bundle args = new Bundle();
NewsListFragment fragment = new NewsListFragment();
args.putInt("type", type);
fragment.setArguments(args);
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNewsPresenter = new NewsPresenterImpl(this);
mType = getArguments().getInt("type");
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_newslist, null);
mSwipeRefreshWidget = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_widget);
mSwipeRefreshWidget.setColorSchemeResources(R.color.primary,
R.color.primary_dark, R.color.primary_light,
R.color.accent);
mSwipeRefreshWidget.setOnRefreshListener(this);
mRecyclerView = (RecyclerView)view.findViewById(R.id.recycle_view);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new NewsAdapter(getActivity().getApplicationContext());
mAdapter.setOnItemClickListener(mOnItemClickListener);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnScrollListener(mOnScrollListener);
onRefresh();
private RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
private int lastVisibleI
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& lastVisibleItem + 1 == mAdapter.getItemCount()
&& mAdapter.isShowFooter()) {
//加载更多
LogUtils.d(TAG, "loading more data");
mNewsPresenter.loadNews(mType, pageIndex + Urls.PAZE_SIZE);
private NewsAdapter.OnItemClickListener mOnItemClickListener = new NewsAdapter.OnItemClickListener() {
public void onItemClick(View view, int position) {
NewsBean news = mAdapter.getItem(position);
Intent intent = new Intent(getActivity(), NewsDetailActivity.class);
intent.putExtra("news", news);
View transitionView = view.findViewById(R.id.ivNews);
ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
transitionView, getString(R.string.transition_news_img));
ActivityCompat.startActivity(getActivity(), intent, options.toBundle());
public void showProgress() {
mSwipeRefreshWidget.setRefreshing(true);
public void addNews(List&NewsBean& newsList) {
mAdapter.isShowFooter(true);
if(mData == null) {
mData = new ArrayList&NewsBean&();
mData.addAll(newsList);
if(pageIndex == 0) {
mAdapter.setmDate(mData);
//如果没有更多数据了,则隐藏footer布局
if(newsList == null || newsList.size() == 0) {
mAdapter.isShowFooter(false);
mAdapter.notifyDataSetChanged();
pageIndex += Urls.PAZE_SIZE;
public void hideProgress() {
mSwipeRefreshWidget.setRefreshing(false);
public void showLoadFailMsg() {
if(pageIndex == 0) {
mAdapter.isShowFooter(false);
mAdapter.notifyDataSetChanged();
Snackbar.make(getActivity().findViewById(R.id.drawer_layout), getString(R.string.load_fail), Snackbar.LENGTH_SHORT).show();
public void onRefresh() {
pageIndex = 0;
if(mData != null) {
mData.clear();
mNewsPresenter.loadNews(mType, pageIndex);
2、Model层
  新闻模块的model主要负责从服务器获取新闻列表信息,接口代码如下:
public interface NewsModel {
void loadNews(String url, int type, NewsModelImpl.OnLoadNewsListListener listener);
  实现如下:
package com.lauren.simplenews.news.
import com.lauren.simplenews.beans.NewsB
import com.lauren.simplenews.beans.NewsDetailB
import com.mons.U
import com.lauren.simplenews.news.NewsJsonU
import com.lauren.simplenews.news.widget.NewsF
import com.lauren.simplenews.utils.OkHttpU
import java.util.L
* Description : 新闻业务处理类
* Author : lauren
: 15/12/19
public class NewsModelImpl implements NewsModel {
* 加载新闻列表
* @param url
* @param listener
public void loadNews(String url, final int type, final OnLoadNewsListListener listener) {
OkHttpUtils.ResultCallback&String& loadNewsCallback = new OkHttpUtils.ResultCallback&String&() {
public void onSuccess(String response) {
List&NewsBean& newsBeanList = NewsJsonUtils.readJsonNewsBeans(response, getID(type));
listener.onSuccess(newsBeanList);
public void onFailure(Exception e) {
listener.onFailure("load news list failure.", e);
OkHttpUtils.get(url, loadNewsCallback);
* @param type
private String getID(int type) {
switch (type) {
case NewsFragment.NEWS_TYPE_TOP:
id = Urls.TOP_ID;
case NewsFragment.NEWS_TYPE_NBA:
id = Urls.NBA_ID;
case NewsFragment.NEWS_TYPE_CARS:
id = Urls.CAR_ID;
case NewsFragment.NEWS_TYPE_JOKES:
id = Urls.JOKE_ID;
id = Urls.TOP_ID;
private String getDetailUrl(String docId) {
StringBuffer sb = new StringBuffer(Urls.NEW_DETAIL);
sb.append(docId).append(Urls.END_DETAIL_URL);
return sb.toString();
public interface OnLoadNewsListListener {
void onSuccess(List&NewsBean& list);
void onFailure(String msg, Exception e);
  网络请求使用开源项目OkHttp,OkHttpUtils是对其的封装,具体代码如下:
package com.lauren.simplenews.
import android.os.H
import android.os.L
import com.google.gson.internal.$Gson$T
import com.squareup.okhttp.C
import com.squareup.okhttp.FormEncodingB
import com.squareup.okhttp.OkHttpC
import com.squareup.okhttp.R
import com.squareup.okhttp.RequestB
import com.squareup.okhttp.R
import java.io.IOE
import java.lang.reflect.ParameterizedT
import java.lang.reflect.T
import java.net.CookieM
import java.net.CookieP
import java.util.L
import java.util.concurrent.TimeU
* Description : OkHttp网络连接封装工具类
* Author : lauren
: 15/12/17
public class OkHttpUtils {
private static final String TAG = "OkHttpUtils";
private static OkHttpUtils mI
private OkHttpClient mOkHttpC
private Handler mD
private OkHttpUtils() {
mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS);
//cookie enabled
mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
mDelivery = new Handler(Looper.getMainLooper());
private synchronized static OkHttpUtils getmInstance() {
if (mInstance == null) {
mInstance = new OkHttpUtils();
private void getRequest(String url, final ResultCallback callback) {
final Request request = new Request.Builder().url(url).build();
deliveryResult(callback, request);
private void postRequest(String url, final ResultCallback callback, List&Param& params) {
Request request = buildPostRequest(url, params);
deliveryResult(callback, request);
private void deliveryResult(final ResultCallback callback, Request request) {
mOkHttpClient.newCall(request).enqueue(new Callback() {
public void onFailure(Request request, final IOException e) {
sendFailCallback(callback, e);
public void onResponse(Response response) throws IOException {
String str = response.body().string();
if (callback.mType == String.class) {
sendSuccessCallBack(callback, str);
Object object = JsonUtils.deserialize(str, callback.mType);
sendSuccessCallBack(callback, object);
} catch (final Exception e) {
LogUtils.e(TAG, "convert json failure", e);
sendFailCallback(callback, e);
private void sendFailCallback(final ResultCallback callback, final Exception e) {
mDelivery.post(new Runnable() {
public void run() {
if (callback != null) {
callback.onFailure(e);
private void sendSuccessCallBack(final ResultCallback callback, final Object obj) {
mDelivery.post(new Runnable() {
public void run() {
if (callback != null) {
callback.onSuccess(obj);
private Request buildPostRequest(String url, List&Param& params) {
FormEncodingBuilder builder = new FormEncodingBuilder();
for (Param param : params) {
builder.add(param.key, param.value);
RequestBody requestBody = builder.build();
return new Request.Builder().url(url).post(requestBody).build();
/**********************对外接口************************/
* @param url
* @param callback
public static void get(String url, ResultCallback callback) {
getmInstance().getRequest(url, callback);
* post请求
* @param url
* @param callback
* @param params
public static void post(String url, final ResultCallback callback, List&Param& params) {
getmInstance().postRequest(url, callback, params);
* http请求回调类,回调方法在UI线程中执行
* @param &T&
public static abstract class ResultCallback&T& {
public ResultCallback(){
mType = getSuperclassTypeParameter(getClass());
static Type getSuperclassTypeParameter(Class&?& subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
ParameterizedType parameterized = (ParameterizedType)
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
* 请求成功回调
* @param response
public abstract void onSuccess(T response);
* 请求失败回调
* @param e
public abstract void onFailure(Exception e);
* post请求参数类
public static class Param {
public Param() {
public Param(String key, String value) {
this.key =
this.value =
  将网络请求进行封装可以减少很多的代码量,并且后期如果我不想用okhttp了,想换成其它的库,修改起来也方便。
3、Presenter层
  View层需要调用Presenter层加载新闻信息,所以Presenter需要提供加载新闻信息的接口:
public interface NewsPresenter {
void loadNews(int type, int page);
  NewsPresenterImpl的构造函数中需要传入View层的接口对象NewView,并且需要创建一个NewsModel对象。Presenter的具体实现:
package com.lauren.simplenews.news.
import com.lauren.simplenews.beans.NewsB
import com.mons.U
import com.lauren.simplenews.news.model.NewsM
import com.lauren.simplenews.news.model.NewsModelI
import com.lauren.simplenews.news.view.NewsV
import com.lauren.simplenews.news.widget.NewsF
import com.lauren.simplenews.utils.LogU
import java.util.L
* Description :
* Author : lauren
: 15/12/18
public class NewsPresenterImpl implements NewsPresenter, NewsModelImpl.OnLoadNewsListListener {
private static final String TAG = "NewsPresenterImpl";
private NewsView mNewsV
private NewsModel mNewsM
public NewsPresenterImpl(NewsView newsView) {
this.mNewsView = newsV
this.mNewsModel = new NewsModelImpl();
public void loadNews(final int type, final int pageIndex) {
String url = getUrl(type, pageIndex);
LogUtils.d(TAG, url);
//只有第一页的或者刷新的时候才显示刷新进度条
if(pageIndex == 0) {
mNewsView.showProgress();
mNewsModel.loadNews(url, type, this);
* 根据类别和页面索引创建url
* @param type
* @param pageIndex
private String getUrl(int type, int pageIndex) {
StringBuffer sb = new StringBuffer();
switch (type) {
case NewsFragment.NEWS_TYPE_TOP:
sb.append(Urls.TOP_URL).append(Urls.TOP_ID);
case NewsFragment.NEWS_TYPE_NBA:
sb.MON_URL).append(Urls.NBA_ID);
case NewsFragment.NEWS_TYPE_CARS:
sb.MON_URL).append(Urls.CAR_ID);
case NewsFragment.NEWS_TYPE_JOKES:
sb.MON_URL).append(Urls.JOKE_ID);
sb.append(Urls.TOP_URL).append(Urls.TOP_ID);
sb.append("/").append(pageIndex).append(Urls.END_URL);
return sb.toString();
public void onSuccess(List&NewsBean& list) {
mNewsView.hideProgress();
mNewsView.addNews(list);
public void onFailure(String msg, Exception e) {
mNewsView.hideProgress();
mNewsView.showLoadFailMsg();
  当用户切换到NewsListFragment界面之后,界面需要展示新闻列表信息给用户。首先NewsListFragment会调用NewsPresenter的loadNews方法,NewsPresenter 的loadNews方法中又会调用NewsModel中的loadNews方法。NewsModel中的loadNews方法中就是加载数据的核心,通过Okhttp请求服务器接口获取数据,无论数据获取成功与否,都会通过OnLoadNewsListener接口回调给NewsPresenter 。如果获取成功,NewsPresenter 会调用NewsView的addNews方法将获取的新闻列表信息展示到RecyclerView。如果获取失败,则调用NewsView的showLoadFialMsg方法向用户提示失败信息。
  以上就是新闻列表请求的整个过程。
  源码地址:
  转载请注明出处:
阅读(...) 评论()

我要回帖

更多关于 敏捷开发模式优缺点 的文章

 

随机推荐