Android的网络请求之OkHttp封装


OkHttp的封装

市面上每个人都有自己IDE网络请求封装,比如OKGo、OkHttpUtil、NoHttp都是很不错的国内开发者封装的框架,我封装的更多的是自己随心而为之。主要的一个点是将Request的封装和解析更加自由。

使用的步骤如下

  1. 依赖相关的OkHttp的库,我这里依赖的是3.14.9,因为4.X以上开始支持kotlin啦,书写方式有些许不一样
  2. 依赖GSON库,用于json对象的解析
  3. 你的数据基础对象实现Result
  4. 封装好你自己的网络Request,然后在调用OkHttpUtil.getInstance().syncRequest()/asyncRequest()/downAsync(),来调用同步、异步、下载文件的方法

具体的内容如下

  1. 配置类HttpConfig.java
public class HttpConfig {
    //网络连接时间
    private Long connectTimeout;
    //网络写时间
    private Long writeTimeout;
    //网络读取时间
    private Long readTimeout;
    //缓存的文件夹
    private File cacheDir;
    //自定义拦截器
    private List interceptors;
    //是否打印日志 也可以不用,直接动态改变interceptors的拦截器也行
    private boolean printLog;
}
  1. 请求返回封装Result.java
public interface Result {
    boolean extSuccess();//项目中返回成功的字段,有的是T,有的是Y,有的是200,有的是0等,可以自定义此状态
    T extBody();//返回结果
}
  1. 定义网络的请求回调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();
}
  1. 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();
                }
            }
        }
    }
}
  1. [进阶版]使用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();
}
  1. [高阶版] 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;
    }
}