一:添加依赖
1. 在build.gradle中添加rxjava、retrofit等依赖
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.jakewharton:butterknife:7.0.0'
/** rxjava **/
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
/** retrofit **/
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
/** okhttp **/
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
复制代码
}
2. 加入 OkHttp 配置
// 创建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(1000*60, TimeUnit.SECONDS);//连接超时时间
builder.writeTimeout(1000*60,TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(1000*60,TimeUnit.SECONDS);//读操作超时时间
复制代码
复制代码
3. 加入 retrofit 配置
ApiConfig.BASE_URL = "https://wanandroid.com/";
// 创建 OKHttpClient
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
httpBuilder.connectTimeout(1000*60, TimeUnit.SECONDS);//连接超时时间
httpBuilder.writeTimeout(1000*60,TimeUnit.SECONDS);//写操作 超时时间
httpBuilder.readTimeout(1000*60,TimeUnit.SECONDS);//读操作超时时间
// 创建Retrofit
mRetrofit = new Retrofit.Builder()
.client(httpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
复制代码
复制代码
public class CommentResponse {
private Integer errorCode;
private String errorMsg;
private CommentBean date;
}
public class CommentBean {
private int total;
private int size;
private List<CommentData> datas;
class CommentData{
private int articleId;
private boolean canEdit;
private String content;
private int id;
private String niceDate;
private Date publishDate;
private int rootCommentId;
private int status;
private int toUserId;
private String toUserName;
private int userId;
private String userName;
private int zan;
}
}
复制代码
注意:rxjava|rxandroid版本需要一致、retrofit|rxjava版本一致;如果不一致会报错。
二:新建mvp中的v
我们知道从视图view的角度上看一次完整的请求过程包括:显示加载框–>加载数据成功(加载失败)–>更新UI(提示用户)–>关闭正在加载的框。
而这几个步骤我们可以认为大部分请求都是这样的,那么我们就可以将他封装成一个基类视图IBaseView
-
定义基类视图IBaseView
package bule.souv.com.mvp_rxjava_retrofittest_master.base; /** * 描述:视图基类 * 作者:dc on 2017/2/16 10:59 * 邮箱:597210600@qq.com */ public interface IBaseView<T> { /** * @descriptoin 请求前加载progress * @author dc * @date 2017/2/16 11:00 */ void showProgress(); /** * @descriptoin 请求结束之后隐藏progress * @author dc * @date 2017/2/16 11:01 */ void disimissProgress(); /** * @descriptoin 请求数据成功 * @author dc * @param tData 数据类型 * @date 2017/2/16 11:01 */ void loadDataSuccess(T tData); /** * @descriptoin 请求数据错误 * @author dc * @param throwable 异常类型 * @date 2017/2/16 11:01 */ void loadDataError(Throwable throwable); } 复制代码
将这几个请求步骤也成公共方法,然后子类继承这个基类就能获取到这几个公共方法,避免了每个请求的子view都重复定义
-
定义WeatherView子类视图
/** * 描述:评论信息的mvp中的视图V */ public interface CommentView extends IBaseView<CommentResponse> { } 复制代码
三:新建MVP中的model
M在MVP中主要处理业务数据逻辑;如:网络请求数据、数据库获取数据等等。
我们在此就就是通过网络数据评论数据
- CommentModel的接口定义
**
/**
* 描述:MVP中的M;处理获取网络评论数据
*/
public interface CommentModel<T> {
/**
* @descriptoin 获取网络数据
*/
void loadComment(String questionId, IBaseRequestCallBack<T> iBaseRequestCallBack);
}
复制代码
主要提供两个方法,一个通过questionId来获取数据,IBaseRequestCallBack为数据回调接口,这个在下面会讲到。
- 定义数据的回调接口IBaseRequestCallBack
**
package bule.souv.com.mvp_rxjava_retrofittest_master.base;
/**
* 描述:请求数据的回调接口
* Presenter用于接受model获取(加载)数据后的回调
* 作者:dc on 2017/2/16 11:22
* 邮箱:597210600@qq.com
*/
public interface IBaseRequestCallBack<T> {
/**
* @descriptoin 请求之前的操作
* @author dc
* @date 2017/2/16 11:34
*/
void beforeRequest();
/**
* @descriptoin 请求异常
* @author dc
* @param throwable 异常类型
* @date 2017/2/16 11:34
*/
void requestError(Throwable throwable);
/**
* @descriptoin 请求完成
* @author dc
* @date 2017/2/16 11:35
*/
void requestComplete();
/**
* @descriptoin 请求成功
* @author dc
* @param callBack 根据业务返回相应的数据
* @date 2017/2/16 11:35
*/
void requestSuccess(T callBack);
}
复制代码
请求之前的操作一样、用Throwable来处理请求异常信息、请求完成之后的操作一样、只有请求成功返回的Object不一样,在这里使用T泛型来指定不同的object对象。
- 定义retrofit中service的Api
**
/**
* 描述:retrofit的接口service定义
*/
public interface CommentServiceApi {
@GET("wenda/comments/{questionId}/json?")
Observable<CommentInfoBean> loadCommentsInfo(@Query("questionId") String questionId);
}
复制代码
这里首先需要注意请求的接口地址使用retrofit不要拼接错了。提供了两个参数;
-
定义实现CommentModel的CommentImp
**
public class CommentImp extends BaseModel implements CommentModel<CommentInfoBean> { private Context context = null; private CommentServiceApi commentServiceApi; private CompositeSubscription mCompositeSubscription; public CommentImp(Context mContext) { super(); context = mContext; commentServiceApi = retrofitManager.getService(); mCompositeSubscription = new CompositeSubscription(); } @Override public void loadComment(String questionId, final IBaseRequestCallBack iBaseRequestCallBack) { mCompositeSubscription.add(mCompositeSubscription.loadCommentsInfo(key, city) //将subscribe添加到subscription,用于注销subscribe .observeOn(AndroidSchedulers.mainThread())//指定事件消费线程 .subscribeOn(Schedulers.io()) //指定 subscribe() 发生在 IO 线程 .subscribe(new Subscriber<WeatherInfoBean>() { @Override public void onStart() { super.onStart(); //onStart它总是在 subscribe 所发生的线程被调用 ,如果你的subscribe不是主线程,则会出错,则需要指定线程; iBaseRequestCallBack.beforeRequest(); } @Override public void onCompleted() { //回调接口:请求已完成,可以隐藏progress iBaseRequestCallBack.requestComplete(); } @Override public void onError(Throwable e) { //回调接口:请求异常 iBaseRequestCallBack.requestError(e); } @Override public void onNext(WeatherInfoBean weatherInfoBean) { //回调接口:请求成功,获取实体类对象 iBaseRequestCallBack.requestSuccess(weatherInfoBean); } })); } @Override } 复制代码
因为实现了接口CommentModel所以也实现了接口的两个方法。
新建MVP中的P
P在MVP中主要是视图V和模式M之间的桥梁。
-
定义CommentPresenter接口
**
package bule.souv.com.mvp_rxjava_retrofittest_master.presenter; /** * 描述:MVP中的P接口定义 */ public interface CommentPresenter { /** * @descriptoin 请求评论数据 * @author dc * @return */ void loadWeather(String questionId); } 复制代码
-
定义presenter的基类
上面我们的IBaseCallBack,我们定义了几个回调方法,方法里面都是处理请求之前、之后的结果,这里也可以新建个Presenter的基类用来建立不同的M和V之间的桥梁(因为是公共的方法)只是M和V不同而已。也因为不同的M和V对象,同样我们也用泛型来代替
**
package bule.souv.com.mvp_rxjava_retrofittest_master.base;
/**
* 描述:
* * 代理对象的基础实现 : 一些基础的方法
*
* @param <V> 视图接口对象(view) 具体业务各自继承自IBaseView
* @param <T> 业务请求返回的具体对象
* 作者:dc on 2017/2/16 15:07
* 邮箱:597210600@qq.com
*/
public class BasePresenterImp<V extends IBaseView , T> implements IBaseRequestCallBack<T> {
private IBaseView iBaseView = null; //基类视图
/**
* @descriptoin 构造方法
* @author dc
* @param view 具体业务的视图接口对象
* @date 2017/2/16 15:12
*/
public BasePresenterImp(V view) {
this.iBaseView = view;
}
/**
* @descriptoin 请求之前显示progress
* @author dc
* @date 2017/2/16 15:13
*/
@Override
public void beforeRequest() {
iBaseView.showProgress();
}
/**
* @descriptoin 请求异常显示异常信息
* @author dc
* @param throwable 异常信息
* @date 2017/2/16 15:13
*/
@Override
public void requestError(Throwable throwable) {
iBaseView.loadDataError(throwable);
iBaseView.disimissProgress(); //请求错误,提示错误信息之后隐藏progress
}
/**
* @descriptoin 请求完成之后隐藏progress
* @author dc
* @date 2017/2/16 15:14
*/
@Override
public void requestComplete() {
iBaseView.disimissProgress();
}
/**
* @descriptoin 请求成功获取成功之后的数据信息
* @author dc
* @param callBack 回调的数据
* @date 2017/2/16 15:14
*/
@Override
public void requestSuccess(T callBack) {
iBaseView.loadDataSuccess(callBack);
}
}
复制代码
在代码中我们可以看到,加载前的弹框,加载成功回调给UI,加载失败通知UI错误信息,加载完成关闭弹框等都已经在这里做了一个基础的实现(这就是为什么定义一个基类的原因)。
这里我们通过两个泛型V and T,V表示不同的视图、T表示不同的对象。这样只要在不同的presenter传入不同的V和T就能通过基类来建立不同的视图V和不同的模型M之间的桥梁
- 实现CommentPresenter接口的CommentPresenterImp
**
public class CommentPresenterImp extends BasePresenterImp<CommentView,WeatherInfoBean> implements CommentPresenter { //传入泛型V和T分别为CommentView、CommentInfoBean表示建立这两者之间的桥梁
private Context context = null;
privateCommentModelImp commentModelImp = null;
/**
* @descriptoin 构造方法
* @param view 具体业务的视图接口对象
* @author dc
* @date 2017/2/16 15:12
*/
publicCommentPresenterImp(CommentrView view, Context context) {
super(view);
this.context = context;
this.commentModelImp = new CommentrModelImp(context);
}
@Override
public void loadComment(String questionid
) {
commentModelImp.loadComment(questionid, this);
}
}
复制代码
在类的定义代码中我们继承了基类BasePresenterImp并传入泛型V、T分别为CommentView、CommentInfoBean则表示建立这两者之间的桥梁
也因为我们在BasePresenterImp中实现了IBaseCallBack的回调方法,所以程序Model请求之后通过回调接口调用BasePresenterImp中不同的方法,而我们在不同的方法中处理了视图V的界面,从而P就建立了M的数据处理和V视图的显示处理之间的桥梁
Activity或Fragment的实现
这里面的代码处理都很简单,因为MVP的好处讲activity的M和V分离开了的好处。
**
package bule.souv.com.mvp_rxjava_retrofittest_master;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import bule.souv.com.mvp_rxjava_retrofittest_master.bean.WeatherInfoBean;
import bule.souv.com.mvp_rxjava_retrofittest_master.presenter.WeatherPresenterImp;
import bule.souv.com.mvp_rxjava_retrofittest_master.view.WeatherView;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity implements WeatherView{
@Bind(R.id.toolbar)
Toolbar toolbar;
@Bind(R.id.main_getweather_temp_btn)
Button mainGetweatherTempBtn;
@Bind(R.id.main_showweather_temp_tv)
TextView mainShowweatherTempTv;
@Bind(R.id.fab)
FloatingActionButton fab;
/** 对象定义 **/
private WeatherPresenterImp weatherPresenterImp = null;
private ProgressDialog progressDialog = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
init();
}
/**
* @descriptoin 点击获取温度
* @author
* @param
* @date 2017/2/16 15:52
* @return
*/
@OnClick(R.id.main_getweather_temp_btn)
public void setOnClickRequestWeatherBtn(){
weatherPresenterImp.loadWeather("c5bb749112664353af44bc99ed263857", "长沙");
}
/**
* @descriptoin 初始化
* @author dc
* @date 2017/2/16 15:44
*/
private void init(){
weatherPresenterImp = new WeatherPresenterImp(this,this);
progressDialog = new ProgressDialog(MainActivity.this);
// progressDialog.setTitle();
progressDialog.setMessage("正在请求获取数据,请稍等!!!");
}
@Override
public void showProgress() {
if(progressDialog != null && !progressDialog.isShowing()){
progressDialog.show();
}
}
@Override
public void disimissProgress() {
if(progressDialog != null && progressDialog.isShowing()){
progressDialog.dismiss();
}
}
@Override
public void loadDataSuccess(WeatherInfoBean tData) {
String temperature = tData.getResult().getRealtime().getWeather().getTemperature();
mainShowweatherTempTv.setVisibility(View.VISIBLE);
mainShowweatherTempTv.setText("当前的气温为:" + temperature + "℃");
}
@Override
public void loadDataError(Throwable throwable) {
String errorMsg = throwable.getMessage();
mainShowweatherTempTv.setVisibility(View.VISIBLE);
mainShowweatherTempTv.setText(errorMsg);
}
@Override
protected void onStop() {
super.onStop();
//在退出之后注销subscribe
weatherPresenterImp.unSubscribe();
}
}