Java tutorial
/* * ImageHelper.java * * Tigase Android Messenger * Copyright (C) 2011-2016 "Tigase, Inc." <office@tigase.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. Look for COPYING file in the top folder. * If not, see http://www.gnu.org/licenses/. */ package org.tigase.messenger.phone.pro.utils; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.ComponentCallbacks2; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.os.Build; import android.support.v4.util.LruCache; import android.util.Log; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Class implements generic image in-memory caching feature to ensure that we * have one memory cache for all images (to reduce memory usage and protect * against OutOfMemory). * * @author andrzej */ public class ImageHelper { private static final String TAG = "ImageHelper"; public static float density = 1; protected static LruCache<String, Bitmap> memCache = null; private static Set<Bitmap> placeHolders = new HashSet<Bitmap>(); private static ConcurrentHashMap<String, BitmapDiskLruCache> diskCaches = new ConcurrentHashMap<String, BitmapDiskLruCache>(); protected static void initialize(Context context) { if (memCache == null) { // Get memory class of this device, exceeding this amount will throw // an OutOfMemory exception. final int memClass = ((android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)) .getMemoryClass(); // Use 1/8th of the available memory for this memory cache. final int cacheSize = 1024 * 1024 * memClass / 8; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { memCache = new LruCache<String, Bitmap>(cacheSize) { @TargetApi(12) @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in bytes rather than // number of items. Ignoring placeholder bitmap as well. return placeHolders.contains(bitmap) ? 0 : bitmap.getByteCount(); } }; } else { // below SDK 12 there is no getByteCount method memCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in bytes rather than // number of items. Ignoring placeholder bitmap as well. return placeHolders.contains(bitmap) ? 0 : (bitmap.getRowBytes() * bitmap.getHeight()); } }; } // maps images cache BitmapDiskLruCache diskCache = new BitmapDiskLruCache(); diskCache.initialize(context, "maps", 10 * 1024 * 1024); diskCaches.put("maps", diskCache); // images from files shared with or by us diskCache = new BitmapDiskLruCache(); diskCache.initialize(context, "images-mini", 10 * 1024 * 1024); diskCaches.put("images-mini", diskCache); } } protected static void addPlaceHolder(Bitmap placeHolder) { placeHolders.add(placeHolder); } @SuppressLint("NewApi") public static void onTrimMemory(int level) { int count = 0; if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { count = 10; if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { count = 0; } } else return; int size = 0; if (count > 0) { for (Bitmap b : placeHolders) { size += b.getByteCount(); } } int trimSize = placeHolders.size() == 0 ? 0 : ((count * size) / placeHolders.size()); Log.v(TAG, "trim image cache from " + memCache.size() + " to " + trimSize + " to reduce memory usage, max size " + memCache.maxSize()); memCache.trimToSize(trimSize); } public static void put(String type, String key, Bitmap bitmap) { memCache.put(key, bitmap); BitmapDiskLruCache diskCache = diskCaches.get(type); if (diskCache != null) { diskCache.put(key, bitmap); } } public static Bitmap get(String type, String key) { Bitmap value = memCache.get(key); if (value == null) { BitmapDiskLruCache diskCache = diskCaches.get(type); if (diskCache != null) { value = diskCache.get(key); } } return value; } public static String hashKey(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private static String bytesToHexString(byte[] bytes) { // http://stackoverflow.com/questions/332079 StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } public static class BitmapDiskLruCache extends DiskLruCache<Bitmap> { @Override protected Bitmap decode(org.tigase.messenger.phone.pro.utils.DiskLruCache.Entry e) { FileInputStream fis = null; try { fis = new FileInputStream(e.file); return BitmapFactory.decodeFileDescriptor(fis.getFD()); } catch (Exception ex) { ex.printStackTrace(); return null; } finally { if (fis != null) { try { fis.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } @Override protected void encode(org.tigase.messenger.phone.pro.utils.DiskLruCache.Entry e, Bitmap value) { FileOutputStream fos = null; try { fos = new FileOutputStream(e.file); value.compress(CompressFormat.PNG, 100, fos); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } } }