注意Rxjava配合Retrofit进行网络请求进行了更新,对Rxjava生命周期处理更加合理,详情请看Demo
最近看了许多关于Rxjava2.0,Retrofit及MVP相关的文章,收货颇多,于是忍不住想自己将这几天所学的东西整理一遍,便于以后看到这篇文章的人能很方便的去使用.如果这些知识还不了解的可以去看以下几篇文章:
MVP教程
Rxjava教程
Retrofit教程
MVP介绍
- 优点
- 模型与视图完全分离,我们可以修改视图而不影响模型;
- 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
- 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
- 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。
如下图:
MVP实际操作
介绍两种不同的MVP的分包方式,区别就是一种相对简单一种相对复杂
相对使用简单的
分包方式如下图:
- common,一般存放一些APP常量,公用的东西
- http,一般存放自己封装的网络请求库
- mvp,存放,model层,presenter层和view层
- presentation,UI展示层,一般会在这个包下在细分activity包,fragment包及自定义view包等等
- util,App常用的一些工具类
步骤介绍
-
第一步 编写BasePreseter,IBaseView,及BaseActivity等基类,代码如下
BasePresenterpublic abstract class BasePresenter
{ //Presenter持有的View protected V mView; //上下文 protected Context mContext; //构造方法让Presenter层持有View层的引用 public BasePresenter(Context context,V view){ this.mContext = context; this.mView = view; } } IBaseView,这里我是空实现,你也可以将一些公用的方法放进去
public interface IBaseView { }
ITestView这里边我写了一个start()方法
public interface ITestView extends IBaseView{ void start(); }
BaseActivity
public abstract class BaseActivity
extends AppCompatActivity { protected P mPresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); initPresenter(); initView(); } protected abstract void initView(); protected abstract void initPresenter(); protected abstract int getLayoutId(); }
-
第二步 编写测试的TestActivity,及TestPreseter
TestActivity代码很简单,就是实现ITestView以及BaseActivity的一些重写的方法public class TestActivity extends BaseActivity
implements ITestView{ private Context mContext; @Override protected void initView() { mPresenter.testPresenter(); } public void testActivity(){ Log.d("print", "拥有ITestView的引用"); } @Override protected void initPresenter() { mContext = this; mPresenter = new TestPresenter(mContext,this); } @Override protected int getLayoutId() { return R.layout.activity_test; } @Override public void start() { testActivity(); } } TestPresenter
public class TestPresenter extends BasePresenter
{ public TestPresenter(Context mContext, ITestView mView) { super(mContext, mView); } public void testPresenter(){ Log.d("print", "拥有TestPresenter的引用"); mView.start(); } } 运行后的效果图如下:
逻辑梳理
以上代码就是一个很简单的MVP模式,View层含有Presenter层的引用,Presenter层同时含有View层的引用,model层如涉及到一些服务,数据库等等的操作,或者从服务器获取到的数据,就可以将他的逻辑写到Presenter层里面,这里我就没演示了,这样的话,就实现了View层和model层的分离,他们都是通过Presenter层来建立联系的.
相对复杂的
传送门
Rxjava+Retrofit+Okhttp封装
-
导入以下几个包
implementation 'io.reactivex.rxjava2:rxjava:2.1.5' implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' implementation 'com.squareup.retrofit2:converter-scalars:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.okhttp3:okhttp:3.9.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0' //Cookie持久化管理(推荐) implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
第一步
创建工具类:RetrofitServiceManager
RetrofitServiceManager特性
RetrofitHelper特性:
单例形式创建Retrofit实例;
- 使用okhttp3作为请求客户端;
- 使用gson作为数据转换器;
- 添加各种拦截器,如日志拦截,请求头拦截,请求参数拦截等等
- 开启数据缓存,无网络时可从缓存读取数据;
- 辅助类静态方法获取RetrofitServiceManager实例。
//看代码
public class RetrofitServiceManager {
private static final int DEFAULT_TIME_OUT = 10;//超时时间5s
private static final int DEFAULT_READ_TIME_OUT = 10;//读取时间
private static final int DEFAULT_WRITE_TIME_OUT = 10;//读取时间
private Retrofit mRetrofit;
private RetrofitServiceManager(){
//OkHttpClient配置
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);
builder.writeTimeout(DEFAULT_WRITE_TIME_OUT,TimeUnit.SECONDS);
builder.cache(new Cache(new File(Environment.getExternalStorageDirectory() + "/RxJavaDemo"),1024*1024*10));
//cookie持久化管理
builder.cookieJar(new PersistentCookieJar(new SetCookieCache(),new SharedPrefsCookiePersistor(App.getInstance())));
addInterceptor(builder);
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.baseUrl(ApiService.BASR_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
/**
* 添加各种拦截器
* @param builder
*/
private void addInterceptor(OkHttpClient.Builder builder) {
// 添加日志拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
HttpHeaderInterceptor httpHeaderInterceptor = new HttpHeaderInterceptor.Builder().build();
//日志拦截
builder.addInterceptor(loggingInterceptor);
//头部参数拦截
builder.addInterceptor(httpHeaderInterceptor);
//缓存拦截
builder.addInterceptor(new HttpCacheInterceptor());
//请求参数拦截
builder.addInterceptor(new CommonParamsInterceptor());
}
//单例 饿汉模式
private static class SingletonHolder{
private static RetrofitServiceManager retrofitServiceManager = new RetrofitServiceManager();
}
public static RetrofitServiceManager getInstance(){
return SingletonHolder.retrofitServiceManager;
}
//获取Service实例
public T creat(Class tClass){
return mRetrofit.create(tClass);
}
}
第二步
RxJava封装,再Retrofit中使用RxJava,需要封装的地方仅有2个地方,
- 切换线程操作
- 响应结果处理:onComplete()方法可选,通用错误响应,保留onSuccess()供用户调用
假设我们的Api返回结果如下
{
"code": 0 //0代表成功 非0均为失败
"msg": ""
"model":{}
}
为此,我们创建响应结果的基类:BaseResponse
public class BaseResponse {
private int code;
private String msg;
private T model;
public T getData() {
return model;
}
public void setData(T model) {
this.model = model;
}
public void setCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public boolean isSuccess(){
return code == 0;
}
}
基于以上响应实体类,我们创建RxJava订阅者的封装基类:RxSubcriber
public abstract class RxSubcriber implements Observer> {
private ProgressDialog mProgressDialog;
private Disposable disposable;
private BaseActivity context;
private String errorMsg;
public RxSubcriber(BaseActivity context){
this.context = context;
}
@Override
public void onSubscribe(Disposable d) {
disposable = new CompositeDisposable();
showLoading();
}
@Override
public void onNext(BaseResponse value) {
if(!value.isSuccess()){
ApiException apiException = new ApiException(value.getCode(),value.getMsg());
onError(apiException);
return;
}
onSuccess(value.getData());
}
@Override
public void onError(Throwable e) {
if (e instanceof IOException) {
/** 没有网络 */
errorMsg = "Please check your network status";
} else if (e instanceof HttpException) {
/** 网络异常,http 请求失败,即 http 状态码不在 [200, 300) 之间, such as: "server internal error". */
errorMsg = ((HttpException) e).response().message();
} else if (e instanceof ApiException) {
/** 网络正常,http 请求成功,服务器返回逻辑错误 */
errorMsg = ((ApiException)e).getMsg();
} else {
/** 其他未知错误 */
errorMsg = !TextUtils.isEmpty(e.getMessage()) ? e.getMessage() : "unknown error";
}
dismissLoading();
new AlertDialog.Builder(context)
.setTitle("提示")
.setMessage(errorMsg)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
if(!disposable.isDisposed()){
disposable.dispose();
}
}
}).show();
}
@Override
public void onComplete() {
dismissLoading();
Log.d("print", "-->执行了完成的方法");
}
public abstract void onSuccess(T t);
private void showLoading(){
if(mProgressDialog == null){
mProgressDialog = new ProgressDialog(context);
mProgressDialog.setMessage("正在加载中...");
mProgressDialog.show();
}
}
private void dismissLoading(){
if(mProgressDialog != null){
mProgressDialog.dismiss();
}
}
}
这里主要处理了返回的数据,错误异常的统一处理,以及Dialog加载框的处理.
接下来,对线程切换操作再做一个封装:RxJavaHelper
public class RxjavaHelper {
/**
* 切换线程操作
* @return Observable转换器
*/
public static ObservableTransformer observeOnMainThread() {
return new ObservableTransformer() {
@Override
public ObservableSource apply(Observable upstream) {
return upstream.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
基本封装完毕,现在Api的请求如下:
RetrofitServiceManager.getInstance().creat(ApiService.class)
.getHome()
.compose(RxjavaHelper.>>observeOnMainThread())
.subscribe(new RxSubcriber>(this) {
@Override
public void onSuccess(List o) {
Log.d("print", "--->" + o);
}
});
现在看看请求结果:
OK,还可以,Retrofit + RxJava2.0 封装就暂时这样了。如果使用过程有什么问题再修改修改!!
最后附上项目Demo