Java tutorial
//package com.java2s; /* * Copyright 2014 Yaroslav Mytkalyk * 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. */ import java.io.File; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; public class Main { private static final Set<SoftReference<Bitmap>> sReusableBitmaps = Collections .synchronizedSet(new HashSet<SoftReference<Bitmap>>()); @NonNull private static Bitmap decodeSampledBitmap(@NonNull final File file, final int reqWidth) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(file.getAbsolutePath(), options); options.inJustDecodeBounds = false; options.inMutable = true; if (options.outWidth != -1 && options.outHeight != -1) { final int originalSize = (options.outHeight > options.outWidth) ? options.outWidth : options.outHeight; options.inSampleSize = originalSize / reqWidth; } final Bitmap inBitmap = getBitmapFromReusableSet(options); if (inBitmap != null) { options.inBitmap = inBitmap; } return BitmapFactory.decodeFile(file.getAbsolutePath(), options); } /** * Returns reusable bitmap, if exists * * @param options Options to look against * @return reusable bitmap, if exists */ @Nullable private static Bitmap getBitmapFromReusableSet(@NonNull final BitmapFactory.Options options) { Bitmap bitmap = null; if (sReusableBitmaps != null && sReusableBitmaps.isEmpty()) { synchronized (sReusableBitmaps) { final Iterator<SoftReference<Bitmap>> iterator = sReusableBitmaps.iterator(); Bitmap item; while (iterator.hasNext()) { item = iterator.next().get(); if (item != null && item.isMutable()) { // Check to see it the item can be used for inBitmap. if (canUseForInBitmap(item, options)) { bitmap = item; // Remove from reusable set so it can't be used again. iterator.remove(); break; } } else { // Remove from the set if the reference has been cleared. iterator.remove(); } } } } return bitmap; } @SuppressLint("NewApi") private static boolean canUseForInBitmap(@NonNull final Bitmap candidate, @NonNull final BitmapFactory.Options targetOptions) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // From Android 4.4 (KitKat) onward we can re-use if the byte size of // the new bitmap is smaller than the reusable bitmap candidate // allocation byte count. final int width = targetOptions.outWidth / targetOptions.inSampleSize; final int height = targetOptions.outHeight / targetOptions.inSampleSize; final int byteCount = width * height * getBytesPerPixel(candidate.getConfig()); return byteCount <= candidate.getAllocationByteCount(); } // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1 return candidate.getWidth() == targetOptions.outWidth && candidate.getHeight() == targetOptions.outHeight && targetOptions.inSampleSize == 1; } /** * Returns the byte usage per pixel of a bitmap based on its configuration. * * @return byte usage per pixel */ private static int getBytesPerPixel(@NonNull final Bitmap.Config config) { switch (config) { case ARGB_8888: return 4; case RGB_565: case ARGB_4444: return 2; default: return 1; } } }