近些年很火的Retrofit+RxJava网络请求框架,功能强大,结构合理,使用简单,最近简单研究了一下,结合MVP模式记录一下~
Retrofit
retrofit是一款针对Android网络请求的开源框架,它与okhttp一样出自Square公司。Rotrofit2.0的网络框架全部交给了okhttp来实现,Android N之后Apache的httpclient已经被Google从SDK中移除,Okhttp则成功上位。Retrofit的网络请求实现风格与URLconnection和httpClient有较大的差别。创建请求的时候需要先创建基于注解的服务接口(不了解的可以先了解一下注解),进行网络请求的时候再通过Retrofit.creat()方法来创建请求。以我的理解其实就是对Okhttp进行了一层的封装,而且retrofit可以很好的搭配RxJava使用,所以说retrofit和RxJava更配哦。。
RxJava
”a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。RxJava使异步操作变得非常简单。其实就是观察者模式,观察者与被观察者
MVP
MVP模式是MVC模式在Android上的一种变体,要介绍MVP就得先介绍MVC。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。把Activity的View和Controller抽离出来就变成了View和Presenter,这就是MVP模式。其实MVP模式跟MVC差不多,MVP分离的更细,有利于扩展,特别是项目需求不停的更改时,就能理解到MVP是多么的好用,更重要的代码看上去也非常的简洁
MVP的优点:
1、模型与视图完全分离,我们可以修改视图而不影响模型
2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。
4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)【以上优点参考了百度百科的“MVP模式“】
各自职责:Retrofit 负责 请求的数据 和 请求的结果,使用 接口的方式 呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。
一、Retrofit写一个网络请求:
1.引入Retrofit的包,在build.gradle文件中添加如下配置:
compile 'com.squareup.retrofit2:retrofit:2.3.0'//导入retrofit
compile 'com.google.code.gson:gson:2.6.2'//Gson 库
//下面两个是RxJava 和 RxAndroid
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
compile 'io.reactivex.rxjava2:rxjava:2.x.y'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Model
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
二、ApiServer,定义了一些接口
public interface ApiServer {
@POST("shopping_login.htm")
Observable
}
三、ApiRetrofit,初始化Retrofit、OkHttpClient,加入了拦截器
public class ApiRetrofit {
public final String BASE_SERVER_URL = "https://wawa-api.vchangyi.com/";
private static ApiRetrofit apiRetrofit;
private Retrofit retrofit;
private OkHttpClient client;
private ApiServer apiServer;
private String TAG = "ApiRetrofit";
/**
* 请求访问quest
* response拦截器
*/
private Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.currentTimeMillis();
Response response = chain.proceed(chain.request());
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
MediaType mediaType = response.body().contentType();
String content = response.body().string();
Log.e(TAG, "----------Request Start----------------");
Log.e(TAG, "| " + request.toString() + request.headers().toString());
Log.e(TAG, "| Response:" + content);
Log.e(TAG, "----------Request End:" + duration + "毫秒----------");
return response.newBuilder()
.body(ResponseBody.create(mediaType, content))
.build();
}
};
public ApiRetrofit() {
client = new OkHttpClient.Builder()
//添加log拦截器
.addInterceptor(interceptor)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
//支持RxJava2
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
apiServer = retrofit.create(ApiServer.class);
}
public static ApiRetrofit getInstance() {
if (apiRetrofit == null) {
synchronized (Object.class) {
if (apiRetrofit == null) {
apiRetrofit = new ApiRetrofit();
}
}
}
return apiRetrofit;
}
public ApiServer getApiService() {
return apiServer;
}
}
四、基类
1.BaseView,其中定义了常用的接口
public interface BaseView {
/**
* 显示dialog
*/
void showLoading();
/**
* 隐藏 dialog
*/
void hideLoading();
/**
* 显示错误信息
*
* @param msg
*/
void showError(String msg);
/**
* 错误码
*/
void onErrorCode(BaseModel model);
}
2.BaseModel
public class BaseModel
private int errcode;
private String errmsg;
private T result;
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
}
3.BasePresenter
public class BasePresenter
private CompositeDisposable compositeDisposable;
public V baseView;
protected ApiServer apiServer = ApiRetrofit.getInstance().getApiService();
public BasePresenter(V baseView) {
this.baseView = baseView;
}
/**
* 解除绑定
*/
public void detachView() {
baseView = null;
removeDisposable();
}
/**
* 返回 view
*
* @return
*/
public V getBaseView() {
return baseView;
}
public void addDisposable(Observable> observable, BaseObserver observer) {
if (compositeDisposable == null) {
compositeDisposable = new CompositeDisposable();
}
compositeDisposable.add(observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(observer));
}
public void removeDisposable() {
if (compositeDisposable != null) {
compositeDisposable.dispose();
}
}
}
4.BaseObserver,主要处理了常见的错误
public abstract class BaseObserver
protected BaseView view;
/**
* 解析数据失败
*/
public static final int PARSE_ERROR = 1001;
/**
* 网络问题
*/
public static final int BAD_NETWORK = 1002;
/**
* 连接错误
*/
public static final int CONNECT_ERROR = 1003;
/**
* 连接超时
*/
public static final int CONNECT_TIMEOUT = 1004;
public BaseObserver(BaseView view) {
this.view = view;
}
@Override
protected void onStart() {
if (view != null) {
view.showLoading();
}
}
@Override
public void onNext(T o) {
try {
BaseModel model = (BaseModel) o;
if (model.getErrcode() == 0) {
onSuccess(o);
} else {
if (view != null) {
view.onErrorCode(model);
}
}
} catch (Exception e) {
e.printStackTrace();
onError(e.toString());
}
}
@Override
public void onError(Throwable e) {
if (view != null) {
view.hideLoading();
}
if (e instanceof HttpException) {
// HTTP错误
onException(BAD_NETWORK);
} else if (e instanceof ConnectException
|| e instanceof UnknownHostException) {
// 连接错误
onException(CONNECT_ERROR);
} else if (e instanceof InterruptedIOException) {
// 连接超时
onException(CONNECT_TIMEOUT);
} else if (e instanceof JsonParseException
|| e instanceof JSONException
|| e instanceof ParseException) {
// 解析错误
onException(PARSE_ERROR);
} else {
if (e != null) {
onError(e.toString());
} else {
onError("未知错误");
}
}
}
private void onException(int unknownError) {
switch (unknownError) {
case CONNECT_ERROR:
onError("连接错误");
break;
case CONNECT_TIMEOUT:
onError("连接超时");
break;
case BAD_NETWORK:
onError("网络问题");
break;
case PARSE_ERROR:
onError("解析数据失败");
break;
default:
break;
}
}
@Override
public void onComplete() {
if (view != null) {
view.hideLoading();
}
}
public abstract void onSuccess(T o);
public abstract void onError(String msg);
}
5.BaseActivity,实现BaseView,处理了Presenter的生命周期。
public abstract class BaseActivity
extends AppCompatActivity implements BaseView {
public Context context;
private ProgressDialog dialog;
public Toast toast;
protected P presenter;
protected abstract P createPresenter();
protected abstract int getLayoutId();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
setContentView(getLayoutId());
presenter = createPresenter();
initView();
initData();
}
public void initData() {
}
public void initView() {
}
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter != null) {
presenter.detachView();
}
}
/**
* @param s
*/
public void showtoast(String s) {
if (toast == null) {
toast = Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG);
}
toast.show();
}
private void closeLoadingDialog() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
private void showLoadingDialog() {
if (dialog == null) {
dialog = new ProgressDialog(context);
}
dialog.setCancelable(false);
dialog.show();
}
@Override
public void showLoading() {
showLoadingDialog();
}
@Override
public void hideLoading() {
closeLoadingDialog();
}
@Override
public void showError(String msg) {
showtoast(msg);
}
@Override
public void onErrorCode(BaseModel model) {
}
@Override
public void showLoadingFileDialog() {
showFileDialog();
}
@Override
public void hideLoadingFileDialog() {
hideFileDialog();
}
@Override
public void onProgress(long totalSize, long downSize) {
if (dialog != null) {
dialog.setProgress((int) (downSize * 100 / totalSize));
}
}
}
如上,框架已经搭建好了,让我们来看看在实际项目中怎么用。
我们来模拟登陆
1.定义LoginView 继承于BaseView
public interface LoginView extends BaseView {
void onLoginSucc();
}
2.定义LoginPresenter 继承于BasePresenter
public class LoginPresenter extends BasePresenter
public LoginPresenter(LoginView baseView) {
super(baseView);
}
public void login(String name, String pwd) {
addDisposable(apiServer.LoginByRx(name, pwd), new BaseObserver(baseView) {
@Override
public void onSuccess(Object o) {
baseView.onLoginSucc();
}
@Override
public void onError(String msg) {
baseView.showError(msg);
}
});
}
}
3.LoginActivity 中使用
public class LoginActivity extends BaseActivity
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
@Override
protected LoginPresenter createPresenter() {
return new LoginPresenter(this);
}
@Override
protected int getLayoutId() {
return R.layout.activity_login;
}
@Override
public void initView() {
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
mPasswordView = (EditText) findViewById(R.id.password);
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
//示例代码,示例接口
presenter.login(mEmailView.getText().toString(), mPasswordView.getText().toString());
}
});
}
@Override
public void onLoginSucc() {
//Login Succ
showtoast("登录成功");
}
}
这就是简单的Retrofit+rxjava+mvp模式,记录一下,以免以后忘记
下面给大家推荐一款走路就可以挣钱的软件-趣步,不能说赚很多,开始每天几块还是有的。只要大家用的得当还是可以挣很多的,我也在玩这个软件,实名认证就可以赚糖果了,一个糖果目前均价在3.2美元左右。实名认证的第一个月会有14个糖果的,可以直接卖掉,也可以复投继续挣钱~(实名认证是需要9毛钱的哈,如果不相信的话就不要尝试啦),相信我的,加我Q192324279,我拉你进群。