最近新开了一个新项目,准备用一下retrofit +rxjava 来做网络请求库。查看了一些牛人的博客,借鉴封装了一下自己的网络请求库
参考:http://www.zhimengzhe.com/Androidkaifa/291654.html
https://blog.csdn.net/silenceoo/article/details/75037576
封装后的使用:(取消订阅在BaseActivity 中)
RetrofitUtils.getInstance()
.createService(ApiService.class).getUserInfo(1)
.compose(DeafaultTransformer.<BaseBean<UserInfo>>create())
.subscribe(new DefaultObserver<UserInfo>(this, true) {
@Override
public void onSuccess(BaseBean<UserInfo> response) {
// 访问成功
}
});
app 下的 build.gradle 中添加引用库:
implementation 'io.reactivex.rxjava2:rxjava:2.0.3'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Model
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'// 日志打印工具
例如:
一个获取用户信息的接口: http://wecome.my.book/getUserInfo?versoin=1(假的)
请求用户信息 返回一段Json 串:
{"code": 200, "message": "成功",
"data":{
"name":"小明"
"sex": "男"
"age": 18
}
}
一般 应用的接口都统一返回的请求信息
所以可以对实体类进行封装:
BaseBen.class
public class BaseBean<T> implements Serializable {
private static int SUCCESS_CODE = 200;//接口访问成功的code
private int code;
private String message;
private T data;
/**
* 是否成功获取到数据
*/
public boolean isSuccess() {
return getCode() == SUCCESS_CODE;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
实体类: UserInfo.class
public class UserInfo {
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
定义接口类:
public interface ApiService {
String baseUrl = "http://welcome.my.book/";
@GET("getUserInfo")
Observable<BaseBean<UserInfo>> getUserInfo(@Query("version") int version);
}
封装RetrofitUtils ,创建Retrofit以及添加拦截器:
内部使用静态内部类 单利模式
import android.util.Log;
import com.better.skygo.http.interceptor.HttpHeaderInterceptor;
import com.better.skygo.http.interceptor.LogInterceptor;
import com.better.skygo.utils.LogUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitUtils {
private static RetrofitUtils utils;
private final long CONNECT_TIME = 10;
private final long READ_TIME = 10;
private OkHttpClient mClient;
private Retrofit mRetrofit;
private RetrofitUtils() {
// 使用 com.squareup.okhttp3:logging-interceptor:3.8.0 日志工具
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
try {
String text = URLDecoder.decode(message, "utf-8");
LogUtils.d(text);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
LogUtils.d(message);
}
}
});
// 日志显示的级别 BODY、NONE、BASIC
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// 初始化 OkHttpClient
mClient = new OkHttpClient.Builder()
.connectTimeout(CONNECT_TIME, TimeUnit.SECONDS)//连接超时
.readTimeout(READ_TIME, TimeUnit.SECONDS)//读取超时
.addInterceptor(new HttpHeaderInterceptor())
.addInterceptor(interceptor)// 加入日志拦截
// .addNetworkInterceptor(new HeadInterceptor) //加入head头
// .cache() 设置缓存
.build();
// 初始化 Retrofit
mRetrofit = new Retrofit.Builder()
.baseUrl(ApiService.baseUrl)
.client(mClient)
.addConverterFactory(GsonConverterFactory.create())//添加Gson解析
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())// 添加 rxjava 支持
.build();
}
private static class SingletonHolder {
private static final RetrofitUtils INSTANCE = new RetrofitUtils();
}
public static RetrofitUtils getInstance() {
return SingletonHolder.INSTANCE;
}
// 创建网络接口 ApiService
public <T> T createService(Class<T> clazz) {
return mRetrofit.create(clazz);
}
}
封装线程转换器:
每一个请求中都会处理判断 code,根据结果 使用 observeOn和subscribeOn来切换线程。RxJava提供了一种解决方案:Transformer(转换器)。所以需要进行封装:
import com.better.skygo.base.BaseBean;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
/**
* Describe: 设置网络 请求线程 和 结果处理线程
*/
public class DeafaultTransformer<T> implements ObservableTransformer<T, T> {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).map(new Function<T, T>() {
@Override
public T apply(T t) throws Exception {
return t;
}
});
}
public static <T> DeafaultTransformer<T> create() {
return new DeafaultTransformer<>();
}
}
定义BaseImpl接口:
包含 网络请求加载框,以及retrofit生命周期管理
import io.reactivex.disposables.Disposable;
/**
* Describe: 接口访问 弹窗 与 rxjava 取消订阅
*/
public interface BaseImpl {
//加入订阅
boolean addRxDestroy(Disposable disposable);
//移除订阅
void remove(Disposable disposable);
/**
* 显示ProgressDialog
*/
void showProgress(String msg);
/**
* 取消ProgressDialog
*/
void dismissProgress();
}
构造DefaultObserver:
在DefaultObserver中对服务器异常和网络异常进行处理,加载框ProgressDialog和生命周期管理也在此类中完成。
import android.text.TextUtils;
import android.util.Log;
import com.better.skygo.base.BaseBean;
import com.better.skygo.utils.ToastUtils;
import com.google.gson.JsonParseException;
import org.json.JSONException;
import java.io.InterruptedIOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.text.ParseException;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import retrofit2.HttpException;
import static com.better.skygo.http.DefaultObserver.ExceptionReason.CONNECT_ERROR;
import static com.better.skygo.http.DefaultObserver.ExceptionReason.CONNECT_TIMEOUT;
import static com.better.skygo.http.DefaultObserver.ExceptionReason.PARSE_ERROR;
import static com.better.skygo.http.DefaultObserver.ExceptionReason.UNKNOWN_ERROR;
/**
* Describe:请求结果处理,是否显示加载框
*/
public abstract class DefaultObserver<T> implements Observer<BaseBean<T>> {
private BaseImpl mBaseImpl;
public DefaultObserver(BaseImpl baseImpl) {
mBaseImpl = baseImpl;
}
/**
* @param isShowLoading 是否显示加载动画
*/
protected DefaultObserver(BaseImpl baseImpl, boolean isShowLoading) {
mBaseImpl = baseImpl;
if (isShowLoading) {
mBaseImpl.showProgress("正在加载...");
}
}
@Override
public void onSubscribe(Disposable d) {
// 在onDestroy中取消订阅
mBaseImpl.addRxDestroy(d);
}
@Override
public void onNext(BaseBean<T> response) {
mBaseImpl.dismissProgress();
if (response.isSuccess()) {
onSuccess(response);
} else {
onFail(response);
}
}
@Override
public void onError(Throwable e) {
mBaseImpl.dismissProgress();
if (e instanceof HttpException) { // HTTP错误
onException(ExceptionReason.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 {
onException(UNKNOWN_ERROR);
}
}
@Override
public void onComplete() {
}
/**
* 请求成功
*
* @param response 服务器返回的数据
*/
abstract public void onSuccess(BaseBean<T> response);
/**
* 服务器返回数据,但响应码不为200
*
* @param response 服务器返回的数据
*/
private void onFail(BaseBean<T> response) {
String message = response.getReason();
if (TextUtils.isEmpty(message)) {
ToastUtils.showShort("返回错误");
} else {
ToastUtils.showShort(message);
}
}
/**
* 请求异常
*
* @param reason Exception
*/
private void onException(ExceptionReason reason) {
switch (reason) {
case CONNECT_ERROR:
ToastUtils.showShort("连接错误");
break;
case CONNECT_TIMEOUT:
ToastUtils.showShort("连接超时");
break;
case BAD_NETWORK:
ToastUtils.showShort("网络问题");
break;
case PARSE_ERROR:
ToastUtils.showShort("解析数据失败");
break;
case UNKNOWN_ERROR:
default:
ToastUtils.showShort("未知错误");
break;
}
}
/**
* 请求网络失败原因
*/
public enum ExceptionReason {
/**
* 解析数据失败
*/
PARSE_ERROR,
/**
* 网络问题
*/
BAD_NETWORK,
/**
* 连接错误
*/
CONNECT_ERROR,
/**
* 连接超时
*/
CONNECT_TIMEOUT,
/**
* 未知错误
*/
UNKNOWN_ERROR,
}
}
封装BaseActivity,Fragment与之类似 管理生命周期,以及实现加载框
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.better.skygo.R;
import com.better.skygo.http.BaseImpl;
import com.better.skygo.MyView.MyHttpLodingDialog;
import com.better.skygo.utils.ScreentUtils;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
public class BaseActivity extends AppCompatActivity implements TitleBarBase, BaseImpl {
private CompositeDisposable disposablesDestroy;// 管理Destroy取消订阅者者
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
disposables2Destroy = new CompositeDisposable();
}
@Override
public void showProgress(String msg) {
MyHttpLodingDialog.show(BaseActivity.this, false, msg);
}
@Override
public void dismissProgress() {
MyHttpLodingDialog.cancle();
}
@Override
public boolean addRxDestroy(Disposable disposable) {
if (disposablesDestroy == null) {
throw new IllegalStateException(
"addUtilDestroy should be called between onCreate and onDestroy");
}
disposablesDestroy.add(disposable);
return true;
}
@Override
public void remove(Disposable disposable) {
if (disposablesDestroy == null) {
throw new IllegalStateException("remove should not be called after onDestroy");
}
disposablesDestroy.remove(disposable);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (disposablesDestroy == null) {
throw new IllegalStateException(
"onDestroy called multiple times or onCreate not called");
}
disposablesDestroy.dispose();
disposablesDestroy = null;
}
}
import android.content.Context;
import android.content.DialogInterface;
/**
* 可以自己定义样式
*/
public class MyHttpLodingDialog {
private static android.app.ProgressDialog progressDialog;
public static void show(Context cxt, boolean cancelable, String str) {
try {
progressDialog = new android.app.ProgressDialog(cxt);
progressDialog.setCancelable(cancelable);
progressDialog.setMessage(str);
progressDialog.show();
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
progressDialog.cancel();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void cancle() {
if (progressDialog == null)
return;
if (progressDialog.isShowing())
progressDialog.cancel();
}
}
到这里就完成了。
对这块的封装不太理解的,可以自己手写一遍之后,会收获很多。