Android的网络请求之OkHttp封装
OkHttp的封装
市面上每个人都有自己IDE网络请求封装,比如OKGo、OkHttpUtil、NoHttp都是很不错的国内开发者封装的框架,我封装的更多的是自己随心而为之。主要的一个点是将Request的封装和解析更加自由。
使用的步骤如下
- 依赖相关的OkHttp的库,我这里依赖的是3.14.9,因为4.X以上开始支持kotlin啦,书写方式有些许不一样
- 依赖GSON库,用于json对象的解析
- 你的数据基础对象实现Result
- 封装好你自己的网络Request,然后在调用OkHttpUtil.getInstance().syncRequest()/asyncRequest()/downAsync(),来调用同步、异步、下载文件的方法
具体的内容如下
- 配置类HttpConfig.java
public class HttpConfig {
//网络连接时间
private Long connectTimeout;
//网络写时间
private Long writeTimeout;
//网络读取时间
private Long readTimeout;
//缓存的文件夹
private File cacheDir;
//自定义拦截器
private List interceptors;
//是否打印日志 也可以不用,直接动态改变interceptors的拦截器也行
private boolean printLog;
}
- 请求返回封装Result.java
public interface Result {
boolean extSuccess();//项目中返回成功的字段,有的是T,有的是Y,有的是200,有的是0等,可以自定义此状态
T extBody();//返回结果
}
- 定义网络的请求回调ResultCallback.java
public abstract class ResultCallback {
public Type mType;
public Context context;
public ResultCallback(Context context) {
this.context = context;
mType = getSuperclassTypeParameter(getClass());
}
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
/**
* 网络请求开始的时候 可以用于弹窗的处理等
*/
public abstract void onStart();
/**
* 失败的时候
* @param call 当前的call对象
* @param e 异常
*/
public abstract void onFailure(Call call, Exception e);
/**
* 下载的进度监听
* @param byteRead 已读长度
* @param total 总长度
*/
public void onProgress(long byteRead, long total) {}
//成功返回的数据
public abstract void onSuccess(T response);
//网络请求结束 不管是成功和失败都会走这里,一般用于同一处理UI操作
public abstract void onFinish();
}
- OkHttp的单列OkHttpUtil.java
//SingletonHelper 是一个单列的帮助类,也可以不继承这个类 自己写
public class OkHttpUtil extends SingletonHelper {
private static final int CACHE_SIZE = 10 * 1024 * 1024;
private OkHttpClient httpClient;
private Handler handler = new Handler(Looper.getMainLooper());
@Override
public OkHttpUtil newInstance() {
return new OkHttpUtil(null);
}
public OkHttpUtil(HttpConfig httpConfig) {
if (httpConfig == null) {
httpConfig = new HttpConfig.Builder().build();
}
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (httpConfig != null) {
builder.connectTimeout(httpConfig.getConnectTimeout(), TimeUnit.SECONDS)
.readTimeout(httpConfig.getReadTimeout(), TimeUnit.SECONDS)
.writeTimeout(httpConfig.getWriteTimeout(), TimeUnit.SECONDS);
if (httpConfig.getCacheDir() != null) {
builder.cache(new Cache(httpConfig.getCacheDir(), CACHE_SIZE));
}
// 添加一个请求拦截器
List interceptors = httpConfig.getInterceptors();
//这里对于printLog 的使用可以自定义
if (interceptors != null && interceptors.size() > 0) {
for (Interceptor interceptor : interceptors) {
builder.addInterceptor(interceptor);
}
}
}
httpClient = builder.build();
}
public OkHttpClient getHttpClient() {
return httpClient;
}
//同步请求
public Response syncRequest(Request request) throws IOException {
if (httpClient == null) {
return null;
}
return httpClient.newCall(request).execute();
}
//异步请求
public void asyncRequest(Request request, ResultCallback resultCallback) {
if (httpClient == null) {
return;
}
sendStartCallback(resultCallback);
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
sendFailureCallback(call, e, resultCallback);
}
@Override
public void onResponse(Call call, Response response) {
try {
String string = response.body().string();
if (resultCallback.mType == String.class) {
sendSuccessCallback(string, resultCallback);
} else if (resultCallback.mType == Response.class) {
sendSuccessCallback(response, resultCallback);
} else {
Object result = GSONUtil.jsonToBean(string, resultCallback.mType);
if (null != result) {
sendSuccessCallback(result, resultCallback);
} else {
sendFailureCallback(call, new NullPointerException("数据解析异常"), resultCallback);
}
}
} catch (Exception e) {
sendFailureCallback(call, e, resultCallback);
}
}
});
}
/**
* 下载文件并提供出进度监听
*
* @param url 地址
* @param destFile 下载存放的文件
* @param resultCallback 回调
*/
public void downAsync(String url, String tag, final File destFile, final ResultCallback resultCallback) {
if (httpClient == null || destFile == null) {
return;
}
File parentFile = destFile.getParentFile();
if (parentFile == null) {
return;
}
parentFile.mkdir();
sendStartCallback(resultCallback);
Request request = new Request.Builder()
.tag(tag)
.url(url)
.build();
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
sendFailureCallback(call, e, resultCallback);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream is = null;
byte[] buf = new byte[2048];
int len;
int sum = 0;
FileOutputStream fos = null;
try {
destFile.deleteOnExit();
destFile.createNewFile();
long contentLength = response.body().contentLength();
is = response.body().byteStream();
fos = new FileOutputStream(destFile);
while ((len = is.read(buf)) != -1) {
sum += len;
fos.write(buf, 0, len);
sendProgressCallback(sum, contentLength, resultCallback);
}
sendSuccessCallback(destFile, resultCallback);
fos.flush();
} catch (IOException e) {
sendFailureCallback(call, e, resultCallback);
} finally {
IOUtil.close(is, fos);
}
}
});
}
//开始网络请求
protected void sendStartCallback(final ResultCallback callback) {
if (callback != null) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
callback.onStart();
}
});
}
//网络请求失败
protected void sendFailureCallback(final Call call, final Exception e, final ResultCallback callback) {
if (callback != null) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
callback.onFailure(call, e);
callback.onFinish();
}
});
}
//成功回调
protected void sendSuccessCallback(final Object obj, final ResultCallback callback) {
if (callback != null) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(obj);
callback.onFinish();
}
});
}
//下载进度回调
protected void sendProgressCallback(final long byteRead, final long total, final ResultCallback callback) {
if (callback != null) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
callback.onProgress(byteRead, total);
}
});
}
//全部队列中请求全部取消
public void cancelAll() {
if (null != httpClient) {
httpClient.dispatcher().cancelAll();
}
}
//根据标记取消请求的队列和排队中的队列
public void cancel(String tag) {
if (null != httpClient) {
Dispatcher dispatcher = httpClient.dispatcher();
cancelCall(dispatcher.runningCalls(), tag);// 取消正在进行的请求队列中具有tag标记的
cancelCall(dispatcher.queuedCalls(), tag);//取消待请求队列中具有tag标记的
}
}
//
private void cancelCall(List callList, String tag) {
if (callList != null && callList.size() > 0) {
for (Call call : callList) {
if (call != null && tag.equals(call.request().tag())) {
call.cancel();
}
}
}
}
}
- [进阶版]使用Retrofit+OkHttp
public abstract class ServiceFactory {
//存放根据Retrofit构建产生的Service的class
private static final ConcurrentHashMap serviceMap = new ConcurrentHashMap();
/**
* 需要用户自己构建地址
*
* @param clazz 类
* @param 返回类
* @return
*/
public T createService(Class clazz) {
return createService(clazz, serviceUrl(), OkHttpUtil.getInstance(httpConfig()).getHttpClient());
}
/**
* 根据类和网址创建服务
*
* @param clazz 类
* @param baseUrl 请求地址
* @param 返回类
* @return
*/
public T createService(Class clazz, String baseUrl) {
return createService(clazz, baseUrl, OkHttpUtil.getInstance(httpConfig()).getHttpClient());
}
/**
* 根据类和网址创建服务
*
* @param clazz 类
* @param baseUrl 请求地址
* @param httpClient 客户端 自定义
* @param 返回的泛型
* @return
*/
public T createService(Class clazz, String baseUrl, OkHttpClient httpClient) {
String classKey = clazz.getSimpleName() + baseUrl;
Object service = serviceMap.get(classKey);
if (service == null) {
Retrofit.Builder builder = buildRetrofit(baseUrl, httpClient);
service = builder.build().create(clazz);
serviceMap.put(classKey, service);
}
return (T) service;
}
/**
* 数据解析 GsonConverterFactory.create()
* 网络切换适配 RxJava2CallAdapterFactory.create()
*
* @param url 请的地址
* @param httpClient 自定义的OkHttp客户端
* @return Retrofit 对象
*/
public abstract Retrofit.Builder buildRetrofit(String url, OkHttpClient httpClient);
//网络构建的配置参数
public abstract HttpConfig httpConfig();
public abstract String serviceUrl();
}
- [高阶版] Retrofit+OkHttp+RxJava
public abstract class SimpleObserver implements SingleObserver>, LifecycleObserver {
private Lifecycle mLifecycle;
private Disposable mDisposable;
public SimpleObserver(Lifecycle lifecycle) {
mLifecycle = lifecycle;
}
@Override
public void onSubscribe(Disposable disposable) {
mDisposable = disposable;
if (mLifecycle != null) {
mLifecycle.addObserver(this);
}
onStart();
}
@Override
public void onSuccess(Result tResult) {
if (null == tResult || !tResult.extSuccess()) {
onFailure(404, "服务器异常,请稍后尝试");
} else {
if (tResult.extSuccess()) {
onResult(tResult.extBody());
}
}
onHttpEnd();
}
@Override
public void onError(Throwable throwable) {
if (isNetError(throwable)) {
if (throwable instanceof SocketTimeoutException) {
onFailure(500, "请求超时,请检查网络");
} else {
onFailure(500, "您的网络好像有问题,请检查网络");
}
} else {
onFailure(404, "服务器异常,请稍后尝试");
}
onHttpEnd();
}
/**
* 网络请求开始
*/
public abstract void onStart();
/**
* 网络请求返回的对象
*
* @param result 结果对象
*/
public abstract void onResult(T result);
/**
* 请求失败
*
* @param errorCode 错误码
* @param errorMessage 错误信息
*/
public abstract void onFailure(int errorCode, String errorMessage);
public void onHttpEnd() {
//解除与lifecycle的绑定。
if (mLifecycle != null) {
mLifecycle.removeObserver(this);
}
//动释放
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
}
}
private static boolean isNetError(Throwable throwable) {
return throwable instanceof HttpException || throwable instanceof SocketTimeoutException ||
throwable instanceof ConnectException || throwable instanceof UnknownHostException;
}
}