Java tutorial
/* * Copyright (C) 2015 Square, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package retrofit; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static retrofit.Utils.closeQuietly; import java.io.IOException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import android.os.Handler; import android.os.Looper; import android.os.Process; import android.text.TextUtils; import com.kubeiwu.easyandroid.cache.volleycache.Cache; import com.kubeiwu.easyandroid.cache.volleycache.Cache.Entry; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Protocol; import com.squareup.okhttp.Request; import com.squareup.okhttp.ResponseBody; public final class KOkHttpCall<T> implements Call<T> { private final OkHttpClient client; private final RequestFactory requestFactory; private final Converter<T> responseConverter; private final Object[] args; private volatile com.squareup.okhttp.Call rawCall; private boolean executed; // Guarded by this. private volatile boolean canceled; KOkHttpCall(OkHttpClient client, RequestFactory requestFactory, Converter<T> responseConverter, Object[] args) { this.client = client; this.requestFactory = requestFactory; this.responseConverter = responseConverter; this.args = args; } // We are a final type & this saves clearing state. @Override public KOkHttpCall<T> clone() { return new KOkHttpCall<>(client, requestFactory, responseConverter, args); } private static final String REQUESTMODEKEY = "RequestMode"; /** * * * @author Administrator * */ interface RequestMode { String LOAD_DEFAULT = "LOAD_DEFAULT";// ?? String LOAD_NETWORK_ONLY = "LOAD_NETWORK_ONLY";// ?? String LOAD_NETWORK_ELSE_CACHE = "LOAD_NETWORK_ELSE_CACHE";// ?? String LOAD_CACHE_ELSE_NETWORK = "LOAD_CACHE_ELSE_NETWORK";// ?? } public interface CacheMode { String LOAD_DEFAULT = REQUESTMODEKEY + " : " + RequestMode.LOAD_DEFAULT; String LOAD_NETWORK_ONLY = REQUESTMODEKEY + " : " + RequestMode.LOAD_NETWORK_ONLY; String LOAD_NETWORK_ELSE_CACHE = REQUESTMODEKEY + " : " + RequestMode.LOAD_NETWORK_ELSE_CACHE; String LOAD_CACHE_ELSE_NETWORK = REQUESTMODEKEY + " : " + RequestMode.LOAD_CACHE_ELSE_NETWORK; } static final String THREAD_PREFIX = "Retrofit-"; static final String IDLE_THREAD_NAME = THREAD_PREFIX + "Idle"; static Executor defaultHttpExecutor() { return Executors.newCachedThreadPool(new ThreadFactory() { @Override public Thread newThread(final Runnable r) { return new Thread(new Runnable() { @Override public void run() { Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); r.run(); } }, IDLE_THREAD_NAME); } }); } public static final Executor cacheExecutor = defaultHttpExecutor(); public static final Executor cacheCallbackExecutor = new MainThreadExecutor(); static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } private Response<T> execCacheRequest(Request request) { if (responseConverter instanceof KGsonConverter) { KGsonConverter<T> converter = (KGsonConverter<T>) responseConverter; Cache cache = converter.getCache(); if (cache == null) { return null; } Entry entry = cache.get(request.urlString());// ?entry if (entry != null && entry.data != null) {// ? MediaType contentType = MediaType.parse(entry.mimeType); byte[] bytes = entry.data; try { com.squareup.okhttp.Response rawResponse = new com.squareup.okhttp.Response.Builder()// .code(200).request(request).protocol(Protocol.HTTP_1_1) .body(ResponseBody.create(contentType, bytes)).build(); return parseResponse(rawResponse, request); } catch (Exception e) { e.printStackTrace(); } } } return null; } @Override public void enqueue(final Callback<T> callback) { synchronized (this) { if (executed) throw new IllegalStateException("Already executed"); executed = true; } final com.squareup.okhttp.Request request = createRequest(); // ----------------------------------------------------------------------cgp String headerValue = request.header("RequestMode"); if (!TextUtils.isEmpty(headerValue)) { switch (headerValue) { case RequestMode.LOAD_NETWORK_ELSE_CACHE:// ?? exeRequest(callback, request, true); return; case RequestMode.LOAD_CACHE_ELSE_NETWORK:// ? // ---------------------? Response<T> response = execCacheRequest(request); if (response != null) { callback.onResponse(response); return; } // ---------------------? // case RequestMode.LOAD_DEFAULT: case RequestMode.LOAD_NETWORK_ONLY: default: break;// } } // ----------------------------------------------------------------------cgp // new ExecutorCallAdapterFactory(null). exeRequest(callback, request, false); } private void exeRequest(final Callback<T> callback, final Request request, final boolean loadnetElseCache) { com.squareup.okhttp.Call rawCall; try { rawCall = client.newCall(request); } catch (Throwable t) { callback.onFailure(t); return; } if (canceled) { rawCall.cancel(); } this.rawCall = rawCall; rawCall.enqueue(new com.squareup.okhttp.Callback() { private void callFailure(Throwable e) { try { callback.onFailure(e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { callback.onResponse(response); } catch (Throwable t) { t.printStackTrace(); } } @Override public void onFailure(Request request, IOException e) { callFailure(e); } @Override public void onResponse(com.squareup.okhttp.Response rawResponse) { Response<T> response; try { response = parseResponse(rawResponse, request); } catch (Throwable e) { if (loadnetElseCache) { cacheExecutor.execute(new CallbackRunnable<T>(callback, cacheCallbackExecutor) { @Override public Response<T> obtainResponse() { return execCacheRequest(request); } }); return; } callFailure(e); return; } callSuccess(response); } }); } public Response<T> execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already executed"); executed = true; } com.squareup.okhttp.Request request = createRequest(); // ----------------------------------------------------------------------cgp String headerValue = request.header("RequestMode"); if (!TextUtils.isEmpty(headerValue)) { switch (headerValue) { case RequestMode.LOAD_NETWORK_ELSE_CACHE:// ?? com.squareup.okhttp.Call rawCall = client.newCall(request); if (canceled) { rawCall.cancel(); } this.rawCall = rawCall; Response<T> response; try { response = parseResponse(rawCall.execute(), request); } catch (Exception e) { response = execCacheRequest(request); } return response; case RequestMode.LOAD_CACHE_ELSE_NETWORK:// ? // ---------------------? response = execCacheRequest(request); if (response != null) { return response; } // ---------------------? // case RequestMode.LOAD_DEFAULT: case RequestMode.LOAD_NETWORK_ONLY: default: break;// } } // ----------------------------------------------------------------------cgp com.squareup.okhttp.Call rawCall = client.newCall(request); if (canceled) { rawCall.cancel(); } this.rawCall = rawCall; return parseResponse(rawCall.execute(), request); } // private com.squareup.okhttp.Call createRawCall() { // return client.newCall(requestFactory.create(args)); // } private com.squareup.okhttp.Request createRequest() { return requestFactory.create(args); } private Response<T> parseResponse(com.squareup.okhttp.Response rawResponse, com.squareup.okhttp.Request request) throws IOException { ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along. rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build(); int code = rawResponse.code(); if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.readBodyToBytesIfNecessary(rawBody); return Response.error(bufferedBody, rawResponse); } finally { closeQuietly(rawBody); } } if (code == 204 || code == 205) { return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body; if (responseConverter instanceof KGsonConverter) { KGsonConverter<T> converter = (KGsonConverter<T>) responseConverter; body = converter.fromBody(catchingBody, request); } else { body = responseConverter.fromBody(catchingBody); } return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } } public void cancel() { canceled = true; com.squareup.okhttp.Call rawCall = this.rawCall; if (rawCall != null) { rawCall.cancel(); } } }