package io.github.yangxlei.bjnetwork; import android.text.TextUtils; import java.io.File; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.TimeUnit; import okhttp3.CacheControl; import okhttp3.Call; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.internal.Util; /** * Created by yanglei on 16/6/23. */ public class BJNetRequestManager { public enum HttpMethod { GET("GET"), POST("POST"), DELETE("DELETE"), PUT("PUT"); String method; HttpMethod(String method) { this.method = method; } public String getMethod() { return method; } } private BJNetworkClient mNetworkClient; private BJNetResourceManager mResourceManager; private WeakHashMap<Object, BJProgressCallback> mProgressCallbacks = new WeakHashMap<>(); public BJNetRequestManager(BJNetworkClient client) { assert (client != null); this.mNetworkClient = client.newBuilder() // 上传进度监听 .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); BJProgressCallback callback = mProgressCallbacks.get(request.tag()); if (callback == null) { return chain.proceed(request); } else { if(callback instanceof BJDownloadCallback) { return chain.proceed(request); } if (request.body() != null) { BJProgressRequestBody requestBody = new BJProgressRequestBody(request.body(), callback); Request newRequest = request.newBuilder().method(request.method(), requestBody).build(); return chain.proceed(newRequest); } else { return chain.proceed(request); } } } }) //增加下载进度拦截器 .addNetResponseInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Response originResponse = chain.proceed(chain.request()); BJProgressCallback callback = mProgressCallbacks.get(chain.request().tag()); if (callback == null) { return originResponse; } if (callback instanceof BJDownloadCallback) { Response response = originResponse.newBuilder() .body(new BJProgressResponseBody(originResponse.body(), originResponse.headers(), callback)) .build(); return response; } else { return originResponse; } } }) .build(); mResourceManager = new BJNetResourceManager(); } public void cancelCalls(Object tag) { mResourceManager.removeAll(tag); } /** * GET 请求接口 * * @param url 请求地址 * @return {@link BJNetCall} */ public BJNetCall newGetCall(String url) { return newGetCall(url, null, 0); } /** * GET 请求接口 * * @param url 请求地址 * @param headers 自定义请求头 * @return {@link BJNetCall} */ public BJNetCall newGetCall(String url, Map<String, String> headers) { return newGetCall(url, headers, 0); } /** * GET 请求接口 * * @param url 请求地址 * @param cacheTime 请求缓存时间, 单位秒. 如果缓存有效, 不会再发起同样的请求,并且在无网情况下返回缓存的响应 * @return {@link BJNetCall} */ public BJNetCall newGetCall(String url, int cacheTime) { return newGetCall(url, null, cacheTime); } /** * GET 请求接口 * * @param url 请求地址 * @param headers 自定义请求头 * @param cacheTime 请求缓存时间, 单位秒. 如果缓存有效, 不会再发起同样的请求,并且在无网情况下返回缓存的响应 * @return {@link BJNetCall} */ public BJNetCall newGetCall(String url, Map<String, String> headers, int cacheTime) { Request request = buildRequest(HttpMethod.GET, null, url, cacheTime, headers); Call call = mNetworkClient.newCall(request); return new RealNetCall(mResourceManager, call, null, mProgressCallbacks); } /** * Post 请求接口 * * @param url 请求地址 * @return {@link BJNetCall} */ public BJNetCall newPostCall(String url, BJRequestBody requestBody) { return newPostCall(url, requestBody, null); } /** * Post 请求接口 * * @param url 请求地址 * @param headers 自定义请求头 * @return {@link BJNetCall} */ public BJNetCall newPostCall(String url, BJRequestBody requestBody, Map<String, String> headers) { Request request = buildRequest(HttpMethod.POST, requestBody == null ? null : requestBody.getRequestBody(), url, 0, headers); Call call = mNetworkClient.newCall(request); return new RealNetCall(mResourceManager, call,null, mProgressCallbacks); } /** * 下载文件 * @param url * @param storageFileOrDir 下载文件存储位置或目录 * @return 下载执行器 */ public BJNetCall newDownloadCall(String url, File storageFileOrDir) { File target = storageFileOrDir; if (target.isDirectory()) { target = new File(target, Util.md5Hex(url)); } Request request = buildRequest(HttpMethod.GET, null, url, 0, null); Call call = mNetworkClient.newCall(request); return new RealNetCall(mResourceManager, call, target, mProgressCallbacks); } /** * 构建网络请求 * * @param method * @param requestBody * @param url * @param cacheTimeSeconds * @param headers * @return */ protected Request buildRequest(HttpMethod method, RequestBody requestBody, String url, int cacheTimeSeconds, Map<String, String> headers) { if (TextUtils.isEmpty(url)) throw new IllegalArgumentException("url is empty!!"); Request.Builder builder = new Request.Builder(); builder.method(method.getMethod(), requestBody); builder.url(url); if (cacheTimeSeconds > 0) { CacheControl cacheControl = new CacheControl.Builder() .maxAge(cacheTimeSeconds, TimeUnit.SECONDS) .build(); builder.cacheControl(cacheControl); } if (headers != null && !headers.isEmpty()) { Iterator<String> iterator = headers.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); String value = headers.get(key); builder.addHeader(key, value); } } // 增加一个 tag 对象, 用于和 callback 建立标识. builder.tag(new Object()); return builder.build(); } public BJNetworkClient getNetworkClient() { return mNetworkClient; } public BJNetResourceManager getResourceManager() { return mResourceManager; } private static class RealNetCall implements BJNetCall { private WeakReference<Call> mWeakCall; private Call mCall; private BJNetResourceManager mResourceManager; private File mDownloadFile; private Map<Object, BJProgressCallback> mProgressCallbacks; private RealNetCall(BJNetResourceManager resourceManager, Call call, File downloadFile, Map<Object, BJProgressCallback> progressCallbacks) { // call 本身会被 OkHttpClient 中的队列缓存. 请求完成之后会被清除. // 在交付 OKHttpClient 执行之前, 对 call 强引用. 执行之后, 对 Call 弱引用 mCall = call; mWeakCall = new WeakReference<>(call); this.mResourceManager = resourceManager; mDownloadFile = downloadFile; mProgressCallbacks = progressCallbacks; } @Override public void cancel() { if (getCall() != null) { getCall().cancel(); } } @Override public BJResponse executeSync(Object tag) throws IOException { if (mCall == null) { throw new IllegalStateException("Already executed."); } mResourceManager.addNetCall(tag, this); try { Response response = mCall.execute(); return new BJResponse(response); } finally { // 取消对 Call 的强引用 mCall = null; } } @Override public void executeAsync(Object tag, BJNetCallback callback) { if (mCall == null) { throw new IllegalStateException("Already executed."); } if (callback == null) { throw new NullPointerException("callback is null."); } if (callback instanceof BJProgressCallback) { mProgressCallbacks.put(mCall.request().tag(), (BJProgressCallback) callback); } if (callback instanceof BJDownloadCallback) { ((BJDownloadCallback)callback).mStorageFile = mDownloadFile; } mResourceManager.addNetCall(tag, this); try { mCall.enqueue(callback); } finally { mCall = null; } } @Override public boolean isCanceled() { if (getCall() == null) { return false; } return getCall().isCanceled(); } @Override public boolean isExecuted() { if (getCall() == null) { // call == null, 说明请求已经完成,被回收了. return false; } return getCall().isExecuted(); } private Call getCall() { if (mCall != null) { return mCall; } else { return mWeakCall.get(); } } } }