OkHttp
核心
IOkHttpClient.java
public interface IOkHttpClient {
//HttpConfig 用于配置自定义网络的配置
HttpConfig httpConfig();
//定义Https相关的内容
X509TrustManager buildTrustManagers();
SSLSocketFactory createSSLSocketFactory();
HostnameVerifier createHostnameVerifier();
// 是否请求打印日志
HttpLogLevel printLevel();
//是否使用缓存
File cacheDir();
}
HttpConfig.java
public class HttpConfig {
//连接时间
private Long connectTimeout;
// 读数据时间
private Long writeTimeout;
//写数据的时间
private Long readTimeout;
//自定义拦截器
private List<Interceptor> interceptors;
}
SimpleHttp.java
//用于创建自己的网络库
public abstract class SimpleHttp implements IOkHttpClient {
protected OkHttpClient mOkHttpClient;
protected int cacheSize = 100 * 1024 * 1024; // 10MB
protected OkHttpClient buildClient() {
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
HttpConfig httpConfig = null == httpConfig() ? new HttpConfig() : httpConfig();
List<Interceptor> interceptors = httpConfig.getInterceptors();
if (interceptors != null && interceptors.size() > 0) {
for (Interceptor interceptor : interceptors) {
builder.addInterceptor(interceptor);
}
}
if (cacheDir() != null) {
builder.cache(new Cache(cacheDir(), cacheSize));
}
SSLSocketFactory sslSocketFactory = createSSLSocketFactory();
X509TrustManager trustManager = buildTrustManagers();
HostnameVerifier hostnameVerifier = createHostnameVerifier();
if (sslSocketFactory != null && trustManager != null) {
builder.sslSocketFactory(sslSocketFactory, trustManager);
}
if (hostnameVerifier != null) {
builder.hostnameVerifier(hostnameVerifier);
}
mOkHttpClient = builder.readTimeout(httpConfig.getReadTimeout(), TimeUnit.SECONDS)//设置读取超时时间
.writeTimeout(httpConfig.getWriteTimeout(), TimeUnit.SECONDS)//设置写的超时时间
.connectTimeout(httpConfig.getConnectTimeout(), TimeUnit.SECONDS)//设置连接超时时间
.retryOnConnectionFailure(false)
.build();
return mOkHttpClient;
}
public void close(Closeable io) {
if (io != null) {
try {
io.close();
} catch (IOException ignored) {
}
}
}
/**
* 全部队列中请求全部取消
*/
public void cancelAll() {
if (null != mOkHttpClient) {
mOkHttpClient.dispatcher().cancelAll();
}
}
/**
* 根据标记取消请求的队列和排队中的队列
*
* @param tag
*/
public void cancel(String tag) {
if (null != mOkHttpClient) {
Dispatcher dispatcher = mOkHttpClient.dispatcher();
cancelCall(dispatcher.runningCalls(), tag);
cancelCall(dispatcher.queuedCalls(), tag);
}
}
private void cancelCall(List<Call> callList, String tag) {
if (callList != null && callList.size() > 0) {
for (Call call : callList) {
if (call != null && tag.equals(call.request().tag())) {
call.cancel();
}
}
}
}
}
加强版
HttpConfig.java
public class HttpConfig {
private Long connectTimeout;
private Long writeTimeout;
private Long readTimeout;
/**
* 拦截器集合
*/
private HandleInterceptor handleInterceptor;
/**
* 自定义拦截器
*/
private List<Interceptor> interceptors;
}
HandleInterceptor.java
public interface HandleInterceptor {
/**
* @param request 请求
* @param chain chain
* @return 新的Request
*/
Request onHttpRequestBefore(Request request, Interceptor.Chain chain);
/**
* 这里可以先客户端一步拿到每一次 Http 请求的结果,如解析成 Json,检测到token 过期后
* * 重新请求 token, 并重新执行请求
*
* @param httResult 返回内容
* @param chain chain
* @param originalResponse 没有修改以前的Response
* @return 新的Response
*/
Response onHttpResponseBefore(String httResult, Interceptor.Chain chain, Response originalResponse);
}
HttpLogLevel.java
public enum HttpLogLevel {
NONE,
BODY,
ALL
}
AppHttpInterceptor.java
public final class AppHttpInterceptor implements Interceptor {
private static final Charset UTF8 = Charset.forName("UTF-8");
private HandleInterceptor handleInterceptor;
private volatile HttpLogLevel level;
private volatile Set<String> headersToRedact = Collections.emptySet();
public AppHttpInterceptor() {
this(HttpLogLevel.NONE, null);
}
public AppHttpInterceptor(HttpLogLevel logLevel) {
this(logLevel, null);
}
public AppHttpInterceptor(HandleInterceptor handleInterceptor) {
this(HttpLogLevel.NONE, handleInterceptor);
}
public AppHttpInterceptor(HttpLogLevel logLevel, HandleInterceptor handleInterceptor) {
this.level = logLevel;
this.handleInterceptor = handleInterceptor;
}
public void redactHeader(String name) {
Set<String> newHeadersToRedact = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
newHeadersToRedact.addAll(headersToRedact);
newHeadersToRedact.add(name);
headersToRedact = newHeadersToRedact;
}
/**
* Change the level at which this interceptor logs.
*/
public AppHttpInterceptor setLevel(HttpLogLevel level) {
if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead.");
this.level = level;
return this;
}
public HttpLogLevel getLevel() {
return level == null ? HttpLogLevel.NONE : level;
}
@Override
public Response intercept(Chain chain) throws IOException {
HttpLogLevel level = getLevel();
Request request = chain.request();
if (handleInterceptor != null) {
request = handleInterceptor.onHttpRequestBefore(request, chain);
}
if (level == HttpLogLevel.NONE) {
return chain.proceed(request);
}
boolean logHeader = level == HttpLogLevel.ALL;
boolean logBody = level == HttpLogLevel.ALL || level == HttpLogLevel.BODY;
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
Connection connection = chain.connection();
String requestStartMessage = "--> "
+ request.method()
+ ' ' + request.url()
+ (connection != null ? " " + connection.protocol() : "");
if (hasRequestBody) {
requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
}
log(requestStartMessage);
if (hasRequestBody) {
// Request body headers are only present when installed as a network interceptor. Force
// them to be included (when available) so there values are known.
if (requestBody.contentType() != null) {
log("Content-Type: " + requestBody.contentType());
}
if (requestBody.contentLength() != -1) {
log("Content-Length: " + requestBody.contentLength());
}
}
if (logHeader) {
Headers headers = request.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
String name = headers.name(i);
// Skip headers from the request body as they are explicitly logged above.
if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
logHeader(headers, i);
}
}
}
if (!logBody || !hasRequestBody) {
log("--> END " + request.method());
} else if (bodyHasUnknownEncoding(request.headers())) {
log("--> END " + request.method() + " (encoded body omitted)");
} else if (requestBody.isDuplex()) {
log("--> END " + request.method() + " (duplex request body omitted)");
} else {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
Charset charset = UTF8;
MediaType contentType = requestBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
log("");
if (isPlaintext(buffer)) {
log(buffer.readString(charset));
log("--> END " + request.method()
+ " (" + requestBody.contentLength() + "-byte body)");
} else {
log("--> END " + request.method() + " (binary "
+ requestBody.contentLength() + "-byte body omitted)");
}
}
long startNs = System.nanoTime();
Response response = chain.proceed(request);
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
ResponseBody responseBody = response.body();
long contentLength = responseBody.contentLength();
String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
log("<-- "
+ response.code()
+ (response.message().isEmpty() ? "" : ' ' + response.message())
+ ' ' + response.request().url()
+ " (" + tookMs + "ms" + bodySize + " body" + ')');
Headers resHeaders = response.headers();
if (logHeader) {
for (int i = 0, count = resHeaders.size(); i < count; i++) {
logHeader(resHeaders, i);
}
}
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.getBuffer();
Long gzippedLength = null;
if ("gzip".equalsIgnoreCase(resHeaders.get("Content-Encoding"))) {
gzippedLength = buffer.size();
try (GzipSource gzippedResponseBody = new GzipSource(buffer.clone())) {
buffer = new Buffer();
buffer.writeAll(gzippedResponseBody);
}
}
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
String bodyString = "";
if (contentLength != 0) {
bodyString = buffer.clone().readString(charset);
}
log("");
if (!logBody || !HttpHeaders.hasBody(response)) {
log("<-- END HTTP");
} else if (bodyHasUnknownEncoding(response.headers())) {
log("<-- END HTTP (encoded body omitted)");
} else {
if (!isPlaintext(buffer)) {
log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)");
return response;
}
log(bodyString);
if (gzippedLength != null) {
log("<-- END HTTP (" + buffer.size() + "-byte, "
+ gzippedLength + "-gzipped-byte body)");
} else {
log("<-- END HTTP (" + buffer.size() + "-byte body)");
}
}
if (handleInterceptor != null && !TextUtils.isEmpty(bodyString)) {
response = handleInterceptor.onHttpResponseBefore(bodyString, chain, response);
}
return response;
}
private void logHeader(Headers headers, int i) {
String value = headersToRedact.contains(headers.name(i)) ? "██" : headers.value(i);
log(headers.name(i) + ": " + value);
}
private void log(String message) {
Platform.get().log(INFO, message, null);
}
/**
* Returns true if the body in question probably contains human readable text. Uses a small sample
* of code points to detect unicode control characters commonly used in binary file signatures.
*/
static boolean isPlaintext(Buffer buffer) {
try {
Buffer prefix = new Buffer();
long byteCount = buffer.size() < 64 ? buffer.size() : 64;
buffer.copyTo(prefix, 0, byteCount);
for (int i = 0; i < 16; i++) {
if (prefix.exhausted()) {
break;
}
int codePoint = prefix.readUtf8CodePoint();
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
return false;
}
}
return true;
} catch (EOFException e) {
return false; // Truncated UTF-8 sequence.
}
}
private static boolean bodyHasUnknownEncoding(Headers headers) {
String contentEncoding = headers.get("Content-Encoding");
return contentEncoding != null
&& !contentEncoding.equalsIgnoreCase("identity")
&& !contentEncoding.equalsIgnoreCase("gzip");
}
}
SimpleHttp.java
public abstract class SimpleHttp implements IOkHttpClient {
//...
protected OkHttpClient buildClient() {
//...
if (printLevel() != null || httpConfig.getHandleInterceptor() != null) {
AppHttpInterceptor httpLogInterceptor = new AppHttpInterceptor(printLevel(), httpConfig.getHandleInterceptor());
builder.addInterceptor(httpLogInterceptor);
}
//...
return mOkHttpClient;
}
//...
}
Retrofit
//1. 添加依赖的retrofit
implementation 'com.squareup.retrofit2:retrofit:2.7.0'
//2. 采用封装的Retrofit来创建自己的Retrofit 网络切换由自己的控制
public abstract class RetrofitFactory {
protected static final Map<String, Object> serviceMap = new ConcurrentHashMap();
protected <T> T createService(Class<T> clazz, String baseUrl) {
return createService(clazz, baseUrl, buildClient());
}
/**
* 根据类和网址创建服务
*
* @param clazz 类
* @param baseUrl 请求地址
* @param httpClient 客户端
* @param <T> 返回的泛型
* @return
*/
protected <T> T createService(Class<T> 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;
}
public abstract Retrofit.Builder buildRetrofit(String url, OkHttpClient httpClient);
public abstract OkHttpClient buildClient();
}
带RxJava
BaseObserver.java
public abstract class BaseObserver<T> implements Observer<T> {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(T t) {
onSuccess(t);
}
@Override
public void onError(Throwable e) {
onFailure(e);
}
@Override
public void onComplete() {
}
public abstract void onSuccess(T result);
public abstract void onFailure(Throwable throwable);
}
// 网络的处理
/**
* 用于RxJava的异常处理
*
* @param observer
* @param <T>
* @return
*/
public <T> ObservableTransformer<T, T> applySchedulers(BaseObserver<T> observer) {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
Observable<T> observable = (Observable<T>) upstream
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(getAppErrorHandler());
observable.subscribe(observer);
return observable;
}
};
}
/**
* 异常的信息处理
*
* @param <T>
* @return
*/
public abstract <T> Function<T, T> getAppErrorHandler();