/** * Asynchronously fulfills the request without a {@link ImageView} or {@link Target}, and invokes * the target {@link Callback} with the result. This is useful when you want to warm up the cache * with an image. * * <p><em>Note:</em> The {@link Callback} param is a strong reference and will prevent your {@link * android.app.Activity} or {@link android.app.Fragment} from being garbage collected until the * request is completed. */ public void fetch(Callback callback) { long started = System.nanoTime(); if (deferred) { throw new IllegalStateException("Fit cannot be used with fetch."); } if (data.hasImage()) { // Fetch requests have lower priority by default. if (!data.hasPriority()) { data.priority(Priority.LOW); } Request request = createRequest(started); String key = createKey(request, new StringBuilder()); if (shouldReadFromMemoryCache(memoryPolicy)) { Bitmap bitmap = picasso.quickMemoryCacheCheck(key); if (bitmap != null) { if (picasso.loggingEnabled) { log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY); } if (callback != null) { callback.onSuccess(); } return; } } Action action = new FetchAction(picasso, request, memoryPolicy, networkPolicy, tag, key, callback); picasso.submit(action); } }
Bitmap hunt() throws IOException { Bitmap bitmap; if (!skipMemoryCache) { bitmap = cache.get(key); if (bitmap != null) { stats.dispatchCacheHit(); loadedFrom = MEMORY; return bitmap; } } bitmap = decode(data); if (bitmap != null) { stats.dispatchBitmapDecoded(bitmap); if (data.needsTransformation() || exifRotation != 0) { synchronized (DECODE_LOCK) { if (data.needsMatrixTransform() || exifRotation != 0) { bitmap = transformResult(data, bitmap, exifRotation); } if (data.hasCustomTransformations()) { bitmap = applyCustomTransformations(data.transformations, bitmap); } } stats.dispatchBitmapTransformed(bitmap); } } return bitmap; }
@Test public void bitmapConfig() throws Exception { for (Bitmap.Config config : Bitmap.Config.values()) { Request data = new Request.Builder(URI_1).config(config).build(); Request copy = data.buildUpon().build(); assertThat(createBitmapOptions(data).inPreferredConfig).isSameAs(config); assertThat(createBitmapOptions(copy).inPreferredConfig).isSameAs(config); } }
/** Create the request optionally passing it through the request transformer. */ private Request createRequest(long started) { int id = nextId.getAndIncrement(); Request request = data.build(); request.id = id; request.started = started; boolean loggingEnabled = picasso.loggingEnabled; if (loggingEnabled) { log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString()); } Request transformed = picasso.transformRequest(request); if (transformed != request) { // If the request was changed, copy over the id and timestamp from the original. transformed.id = id; transformed.started = started; if (loggingEnabled) { log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed); } } return transformed; }
private Bitmap decodeResource(Resources resources, int id, Request data) { BitmapFactory.Options bitmapOptions = createBitmapOptions(data); if (data.hasSize()) { bitmapOptions.inJustDecodeBounds = true; BitmapFactory.decodeResource(resources, id, bitmapOptions); calculateInSampleSize(data.targetWidth, data.targetHeight, bitmapOptions); } return BitmapFactory.decodeResource(resources, id, bitmapOptions); }
private Bitmap decodeStream(InputStream stream, Request data) throws IOException { if (stream == null) { return null; } MarkableInputStream markStream = new MarkableInputStream(stream); stream = markStream; long mark = markStream.savePosition(MARKER); boolean isWebPFile = Utils.isWebPFile(stream); markStream.reset(mark); // When decode WebP network stream, BitmapFactory throw JNI Exception and make app crash. // Decode byte array instead if (isWebPFile) { byte[] bytes = Utils.toByteArray(stream); BitmapFactory.Options options = createBitmapOptions(data); if (data.hasSize()) { options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); calculateInSampleSize( data.maxWidth, data.maxHeight, data.targetWidth, data.targetHeight, options); } return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); } else { BitmapFactory.Options options = createBitmapOptions(data); if (data.hasSize()) { options.inJustDecodeBounds = true; BitmapFactory.decodeStream(stream, null, options); calculateInSampleSize( data.maxWidth, data.maxHeight, data.targetWidth, data.targetHeight, options); markStream.reset(mark); } return BitmapFactory.decodeStream(stream, null, options); } }
static BitmapFactory.Options createBitmapOptions(Request paramRequest) { boolean bool = paramRequest.hasSize(); if (paramRequest.config != null) {} for (int i = 1; ; i = 0) { Object localObject = null; if ((bool) || (i != 0)) { BitmapFactory.Options localOptions = new BitmapFactory.Options(); localOptions.inJustDecodeBounds = bool; localObject = localOptions; if (i != 0) { localOptions.inPreferredConfig = paramRequest.config; localObject = localOptions; } } return (BitmapFactory.Options) localObject; } }
private Bitmap decodeStream(InputStream stream, Request data) throws IOException { if (stream == null) { return null; } BitmapFactory.Options options = null; if (data.hasSize()) { options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; MarkableInputStream markStream = new MarkableInputStream(stream); stream = markStream; long mark = markStream.savePosition(1024); // Mirrors BitmapFactory.cpp value. BitmapFactory.decodeStream(stream, null, options); calculateInSampleSize(data.targetWidth, data.targetHeight, options); markStream.reset(mark); } return BitmapFactory.decodeStream(stream, null, options); }
@Override public void run() { try { Thread.currentThread().setName(Utils.THREAD_PREFIX + data.getName()); result = hunt(); if (result == null) { dispatcher.dispatchFailed(this); } else { dispatcher.dispatchComplete(this); } } catch (IOException e) { exception = e; dispatcher.dispatchRetry(this); } catch (Exception e) { exception = e; dispatcher.dispatchFailed(this); } finally { Thread.currentThread().setName(Utils.THREAD_IDLE_NAME); } }
static Bitmap transformResult(Request data, Bitmap result, int exifRotation) { int inWidth = result.getWidth(); int inHeight = result.getHeight(); int drawX = 0; int drawY = 0; int drawWidth = inWidth; int drawHeight = inHeight; Matrix matrix = new Matrix(); if (data.needsMatrixTransform()) { int targetWidth = data.targetWidth; int targetHeight = data.targetHeight; float targetRotation = data.rotationDegrees; if (targetRotation != 0) { if (data.hasRotationPivot) { matrix.setRotate(targetRotation, data.rotationPivotX, data.rotationPivotY); } else { matrix.setRotate(targetRotation); } } if (data.centerCrop) { float widthRatio = targetWidth / (float) inWidth; float heightRatio = targetHeight / (float) inHeight; float scale; if (widthRatio > heightRatio) { scale = widthRatio; int newSize = (int) Math.ceil(inHeight * (heightRatio / widthRatio)); drawY = (inHeight - newSize) / 2; drawHeight = newSize; } else { scale = heightRatio; int newSize = (int) Math.ceil(inWidth * (widthRatio / heightRatio)); drawX = (inWidth - newSize) / 2; drawWidth = newSize; } matrix.preScale(scale, scale); } else if (data.centerInside) { float widthRatio = targetWidth / (float) inWidth; float heightRatio = targetHeight / (float) inHeight; float scale = widthRatio < heightRatio ? widthRatio : heightRatio; matrix.preScale(scale, scale); } else if (targetWidth != 0 && targetHeight != 0 // && (targetWidth != inWidth || targetHeight != inHeight)) { // If an explicit target size has been specified and they do not match the results bounds, // pre-scale the existing matrix appropriately. float sx = targetWidth / (float) inWidth; float sy = targetHeight / (float) inHeight; matrix.preScale(sx, sy); } } if (exifRotation != 0) { matrix.preRotate(exifRotation); } Bitmap newResult = Bitmap.createBitmap(result, drawX, drawY, drawWidth, drawHeight, matrix, true); if (newResult != result) { result.recycle(); result = newResult; } return result; }
/** * Asynchronously fulfills the request into the specified {@link ImageView} and invokes the target * {@link Callback} if it's not {@code null}. * * <p><em>Note:</em> The {@link Callback} param is a strong reference and will prevent your {@link * android.app.Activity} or {@link android.app.Fragment} from being garbage collected. If you use * this method, it is <b>strongly</b> recommended you invoke an adjacent {@link * Picasso#cancelRequest(android.widget.ImageView)} call to prevent temporary leaking. */ public void into(ImageView target, Callback callback) { long started = System.nanoTime(); if (picasso.checkMainThreadsEnabled) { checkMain(); } if (target == null) { throw new IllegalArgumentException("Target must not be null."); } if (!data.hasImage()) { picasso.cancelRequest(target); if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } return; } if (deferred) { if (data.hasSize()) { throw new IllegalStateException("Fit cannot be used with resize."); } int width = target.getWidth(); int height = target.getHeight(); if (width == 0 || height == 0) { if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } picasso.defer(target, new DeferredRequestCreator(this, target, callback)); return; } data.resize(width, height); } Request request = createRequest(started); String requestKey = createKey(request); if (shouldReadFromMemoryCache(memoryPolicy)) { Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey); if (bitmap != null) { picasso.cancelRequest(target); setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled); if (picasso.loggingEnabled) { log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY); } if (callback != null) { callback.onSuccess(); } return; } } if (setPlaceholder) { setPlaceholder(target, getPlaceholderDrawable()); } Action action = new ImageViewAction( picasso, target, request, memoryPolicy, networkPolicy, errorResId, errorDrawable, requestKey, tag, callback, noFade); picasso.enqueueAndSubmit(action); }