在之前的项目中一直都用着比较老的网络框架,比如volly,okgo,okhttp等等,平时写demo 的时候偶尔也会用到新的框架拿来练练手,这两天写了一个关于retrofit2的案例,分享出来。
大牛们恐怕已经写到烂的了,有不足请多多指教。
demo开始前,先导入retrofit、rxjava相关的jar
project中的build.gradle中添加:
// Retrofit库
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
// gson解析,可以自行替换
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
// 日志的拦截器,也可以自行选择
compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
由于retrofit底层是okhttp实现的,所以导入retrofit的时候已经自动帮你导入了OKHttp3的jar包。
项目结构中dialog包下有一个ProgressHUD.java类,这个是用来请求网络时加载的对话框,使用简单方便,加入包:
//加载对话框
compile 'com.kaopiz:kprogresshud:+'
OK,先封装一个retrofit的请求入口,代码如下:
package com.allen.retrofit2_rxjava2.utils;
import com.allen.retrofit2_rxjava2.ApiAddress;
import com.allen.retrofit2_rxjava2.app.MyApp;
import com.allen.retrofit2_rxjava2.network.AllApi;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* @author: Allen.
* @date: 2018/7/25
* @description: retrofit请求工具类
*/
public class RetrofitUtil {
/**
* 超时时间
*/
private static volatile RetrofitUtil mInstance;
private AllApi allApi;
/**
* 单例封装
*
* @return
*/
public static RetrofitUtil getInstance() {
if (mInstance == null) {
synchronized (RetrofitUtil.class) {
if (mInstance == null) {
mInstance = new RetrofitUtil();
}
}
}
return mInstance;
}
/**
* 初始化Retrofit
*/
public AllApi initRetrofit() {
Retrofit mRetrofit = new Retrofit.Builder()
.client(MyApp.initOKHttp())
// 设置请求的域名
.baseUrl(ApiAddress.api)
// 设置解析转换工厂
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return mRetrofit.create(AllApi.class);
}
}
在Application中初始OKHttpClient 对象,因为有时候每次请求接口的时候都重新去new一个client,在后台接口中可能会导致多个session去请求,导致session失效一直无法请求成功。
MyApp.java
package com.allen.retrofit2_rxjava2.app;
import android.app.Application;
import com.allen.retrofit2_rxjava2.network.CookieReadInterceptor;
import com.allen.retrofit2_rxjava2.network.CookiesSaveInterceptor;
import com.allen.retrofit2_rxjava2.utils.InterceptorUtil;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
/**
* @author: Allen.
* @date: 2018/7/25
* @description: application
*/
public class MyApp extends Application {
public static MyApp myApp;
public static final int TIMEOUT = 60;
private static OkHttpClient mOkHttpClient;
@Override
public void onCreate() {
super.onCreate();
myApp = this;
}
/**
* 全局httpclient
*
* @return
*/
public static OkHttpClient initOKHttp() {
if (mOkHttpClient == null) {
mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)//设置连接超时时间
.readTimeout(TIMEOUT, TimeUnit.SECONDS)//设置读取超时时间
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)//设置写入超时时间
.addInterceptor(InterceptorUtil.LogInterceptor())//添加日志拦截器
//cookie
.addInterceptor(new CookieReadInterceptor())
.addInterceptor(new CookiesSaveInterceptor())
.build();
}
return mOkHttpClient;
}
}
这里说明一下,方便理解后面的代码,.addInterceptor(InterceptorUtil.LogInterceptor())//添加日志拦截器
是请求的日志拦截器,当请求一个api,传的参数,提交方式*(POST or GET…),请求头等信息都会打印出来。
//cookie
.addInterceptor(new CookieReadInterceptor())
.addInterceptor(new CookiesSaveInterceptor())
####这个拦截器是请求图片验证码的时候,把该请求头的cookie 读取之后保存起来,下次请求登录接口时 header 带上该cookie,不然会一直提示验证码错误,这是个坑,要注意。
写api接口,AllApi.java:
package com.allen.retrofit2_rxjava2.network;
import com.allen.retrofit2_rxjava2.ApiAddress;
import com.allen.retrofit2_rxjava2.base.BaseEntry;
import com.allen.retrofit2_rxjava2.bean.Banner;
import com.allen.retrofit2_rxjava2.bean.Login;
import com.allen.retrofit2_rxjava2.bean.ZiXunAll;
import java.util.List;
import java.util.Map;
import io.reactivex.Observable;
import okhttp3.ResponseBody;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
/**
* @author: Allen.
* @date: 2018/7/25
* @description:
*/
public interface AllApi {
/**
* 获取banner
*/
@GET(ApiAddress.getBannerList)
Observable>> getBanner();
/**
* 最新资讯
*/
@GET(ApiAddress.getZixunList)
Observable>> getZixunData();
/**
* 获取图片验证码
*/
@GET(ApiAddress.getVerifyCode)
Observable getVerityCode();
/**
* 登录
*/
@POST(ApiAddress.userLogin)
Observable> userLogin(@Body Map maps);
}
实体bean 就不贴出来了,最后大家可以去下载demo。
简单写MainActivity中的module接口
package com.allen.retrofit2_rxjava2.module;
import android.graphics.Bitmap;
import com.allen.retrofit2_rxjava2.base.BasePresenter;
import com.allen.retrofit2_rxjava2.base.BaseView;
/**
* @author: Allen.
* @date: 2018/7/25
* @description:
*/
public interface MainContract {
interface View extends BaseView {
void setContent(String content); //设置内容
void setCode(Bitmap value); //设置验证码
}
interface presenter extends BasePresenter{
void getCode(); //获取验证码
void userLogin(String user,String pwd,String code); //登录
void getBannerData(); //banner
void getLiveData(); //资讯信息
}
}
Presenter去实现业务如下:
package com.allen.retrofit2_rxjava2.presenter;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.allen.retrofit2_rxjava2.base.BaseEntry;
import com.allen.retrofit2_rxjava2.base.BaseObserver;
import com.allen.retrofit2_rxjava2.bean.Banner;
import com.allen.retrofit2_rxjava2.bean.Login;
import com.allen.retrofit2_rxjava2.bean.ZiXunAll;
import com.allen.retrofit2_rxjava2.module.MainContract;
import com.allen.retrofit2_rxjava2.utils.MainUtil;
import com.allen.retrofit2_rxjava2.utils.RetrofitUtil;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
/**
* @author: Allen.
* @date: 2018/7/25
* @description:
*/
public class MainPresenter implements MainContract.presenter {
private Context context;
private MainContract.View view;
public MainPresenter(Context context, MainContract.View view) {
this.context = context;
this.view = view;
}
/**
* 图片验证码
*/
@Override
public void getCode() {
RetrofitUtil.getInstance().initRetrofit().getVerityCode().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody value) {
InputStream is=value.byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
view.setCode(bitmap);
}
@Override
public void onError(Throwable e) {
view.setContent("失败了----->"+e.getMessage());
}
@Override
public void onComplete() {
}
});
}
/**
* 登录
* @param user
* @param pwd
* @param code
*/
@Override
public void userLogin(String user, String pwd, String code) {
Map map=new HashMap<>();
map.put("userName",user);
map.put("userPwd",pwd);
map.put("verifyCode",code);
RetrofitUtil.getInstance().initRetrofit().userLogin(map)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver(context,MainUtil.loadLogin) {
@Override
protected void onSuccees(BaseEntry t) throws Exception {
if(t.isSuccess()){
view.setContent("Hello---->"+t.getData().getName());
}else {
view.setContent("----->"+t.getMessage());
}
}
@Override
protected void onFailure(Throwable e, boolean isNetWorkError) throws Exception {
view.setContent("失败了----->"+e.getMessage());
}
});
}
/**
* 获取banner
*/
@Override
public void getBannerData() {
RetrofitUtil.getInstance().initRetrofit().getBanner()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver>(context,MainUtil.loadTxt) {
@Override
protected void onSuccees(BaseEntry> t) throws Exception {
MainUtil.printLogger(t.getData().get(0).getTitle());
view.setContent(t.getData().get(0).getContent());
}
@Override
protected void onFailure(Throwable e, boolean isNetWorkError) throws Exception {
view.setContent("失败了----->"+e.getMessage());
}
});
}
/**
* 获取资讯
*/
@Override
public void getLiveData() {
RetrofitUtil.getInstance().initRetrofit().getZixunData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver>(context,MainUtil.loadTxt) {
@Override
protected void onSuccees(BaseEntry> t) throws Exception {
view.setContent("标题:" + t.getData().get(0).getTitle());
}
@Override
protected void onFailure(Throwable e, boolean isNetWorkError) throws Exception {
view.setContent("失败了----->"+e.getMessage());
}
});
}
}
BaseObserver是自定义的,实现Observer,只要请求成功,失败接口就行,代码:
package com.allen.retrofit2_rxjava2.base;
import android.accounts.NetworkErrorException;
import android.content.Context;
import com.allen.retrofit2_rxjava2.dialog.ProgressHUD;
import com.kaopiz.kprogresshud.KProgressHUD;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeoutException;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
/**
* @author: Allen.
* @date: 2018/7/25
* @description: 自定义Observer
*/
public abstract class BaseObserver implements Observer> {
protected Context mContext;
private KProgressHUD progressHUD;
private String labelTxt;
public BaseObserver(Context cxt, String text) {
this.mContext = cxt;
this.labelTxt = text;
progressHUD = ProgressHUD.show(mContext);
}
//开始
@Override
public void onSubscribe(Disposable d) {
onRequestStart();
}
//获取数据
@Override
public void onNext(BaseEntry tBaseEntity) {
try {
onSuccees(tBaseEntity);
} catch (Exception e) {
e.printStackTrace();
}
}
//失败
@Override
public void onError(Throwable e) {
onRequestEnd();
try {
if (e instanceof ConnectException
|| e instanceof TimeoutException
|| e instanceof NetworkErrorException
|| e instanceof UnknownHostException) {
onFailure(e, true); //网络错误
} else {
onFailure(e, false);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
//结束
@Override
public void onComplete() {
onRequestEnd();//请求结束
}
/**
* 返回成功
*
* @param t
* @throws Exception
*/
protected abstract void onSuccees(BaseEntry t) throws Exception;
/**
* 返回失败
*
* @param e
* @param isNetWorkError 是否是网络错误
* @throws Exception
*/
protected abstract void onFailure(Throwable e, boolean isNetWorkError) throws Exception;
protected void onRequestStart() {
if (progressHUD != null) {
progressHUD.setLabel(labelTxt);
}
}
protected void onRequestEnd() {
if (progressHUD != null) {
progressHUD.dismiss();
progressHUD = null;
}
}
}
然后再贴出MainActivity的代码:
package com.allen.retrofit2_rxjava2;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.allen.retrofit2_rxjava2.module.MainContract;
import com.allen.retrofit2_rxjava2.presenter.MainPresenter;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity implements MainContract.View {
private MainPresenter presenter;
@BindView(R.id.btn_login)
Button btn_login;
@BindView(R.id.btn_banner)
Button btn_banner;
@BindView(R.id.btn_zixun)
Button btn_zixun;
@BindView(R.id.et_code)
EditText et_code;
@BindView(R.id.iv_code)
ImageView iv_code;
@BindView(R.id.tv_content)
TextView tv_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
presenter = new MainPresenter(this, this);
presenter.getCode(); //获取图片验证码
}
@OnClick({R.id.btn_login, R.id.btn_banner, R.id.btn_zixun, R.id.iv_code})
public void clickBtn(View view) {
String code = et_code.getText().toString().trim();
switch (view.getId()) {
case R.id.btn_login:
presenter.userLogin("allen234", "allen234", code);
break;
case R.id.btn_banner:
presenter.getBannerData();
break;
case R.id.btn_zixun:
presenter.getLiveData();
break;
case R.id.iv_code:
presenter.getCode();
break;
}
}
@Override
public void setContent(String content) {
if (!TextUtils.isEmpty(content)) {
tv_content.setText(content);
}
}
@Override
public void setCode(Bitmap value) {
//通过imageview,设置图片
iv_code.setImageBitmap(value);
}
}
demo源码地址