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();