/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.imagepipeline.backends.okhttp; import java.io.IOException; import android.net.Uri; import com.facebook.common.logging.FLog; import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.memory.ByteArrayPool; import com.facebook.imagepipeline.memory.PooledByteBuffer; import com.facebook.imagepipeline.memory.PooledByteBufferFactory; import com.facebook.imagepipeline.producers.BaseProducerContextCallbacks; import com.facebook.imagepipeline.producers.Consumer; import com.facebook.imagepipeline.producers.NfpRequestState; import com.facebook.imagepipeline.producers.NetworkFetchProducer; import com.facebook.imagepipeline.producers.ProducerContext; import com.squareup.okhttp.Call; import com.squareup.okhttp.Callback; import com.squareup.okhttp.CacheControl; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import com.squareup.okhttp.ResponseBody; /** * Network fetch producer using OkHttp as a backend. * * <p> OkHttpNetworkFetchProducer supports request cancellation. This feature is enabled * via {@code cancellable} constructor parameter. */ public class OkHttpNetworkFetchProducer extends NetworkFetchProducer<NfpRequestState> { private static final String TAG = "OkHttpNetworkFetchProducer"; private final OkHttpClient mOkHttpClient; private final boolean mCancellable; /** * @param okHttpClient client to use * @param cancellable whether to allow cancellation of submitted requests * @param pooledByteBufferFactory pooled byte buffer factory * @param byteArrayPool pool for stream input/ouptut buffering */ public OkHttpNetworkFetchProducer( OkHttpClient okHttpClient, boolean cancellable, PooledByteBufferFactory pooledByteBufferFactory, ByteArrayPool byteArrayPool) { super(pooledByteBufferFactory, byteArrayPool); mOkHttpClient = okHttpClient; mCancellable = cancellable; } @Override protected NfpRequestState newRequestState( Consumer<CloseableReference<PooledByteBuffer>> consumer, ProducerContext context) { return new NfpRequestState(consumer, context); } @Override protected void fetchImage(final NfpRequestState requestState) { final Uri uri = requestState.getUri(); final Request request = new Request.Builder() .cacheControl(new CacheControl.Builder().noStore().build()) .url(uri.toString()) .get() .build(); final Call call = mOkHttpClient.newCall(request); if (mCancellable) { requestState.getContext().addCallbacks( new BaseProducerContextCallbacks() { @Override public void onCancellationRequested() { call.cancel(); } }); } call.enqueue( new Callback() { @Override public void onResponse(Response response) { final ResponseBody body = response.body(); try { long contentLength = body.contentLength(); if (contentLength < 0) { contentLength = 0; } processResult(requestState, body.byteStream(), (int) contentLength, false); } catch (IOException ioe) { handleException(call, requestState, ioe); } finally { try { body.close(); } catch (IOException ioe) { FLog.w(TAG, "Exception when closing response body", ioe); } } } @Override public void onFailure(final Request request, final IOException e) { handleException(call, requestState, e); } }); } /** * Handles IOExceptions. * * <p> OkHttp notifies callers of cancellations via an IOException. If IOException is caught * after request cancellation, then the exception is interpreted as successful cancellation * and onCancellation is called. Otherwise onFailure is called. */ private void handleException( final Call call, final NfpRequestState requestState, final IOException ioe) { if (call.isCanceled()) { onCancellation(requestState, null); } else { onFailure(requestState, ioe, null); } } }