안드로이드(Android)에서 많은 썸네일(Thumbnail)을 처리하기 위해서 많은 앱들이 1차 메모리, 2차 디스크 캐시를 사용하고 있다. 여기에서 2차 디스크는 용량이 충분하기 때문에 별 이슈가 없다. 하지만, 메모리 캐시의 경우에는 디바이스별로 다르기 때문에 보통은 작은 사이즈로 지정해서 사용하게 된다. 지금 출시되는 안드로이드 디바이스의 앱 메모리 설정을 보면, 이전보다 매우 크게 사용할 수 있는 것을 알수가 있다.
그래서, 메모리 캐시를 더 크게 사용해서, UX의 반응을 더 높이는 방법을 살펴보자. 기본적으로, http://www.sjava.net/332 를 보면, 안드로이드 OS의 설정정보를 읽어서, 디바이스의 정보를 알수가 있겠다.
앱마다 사용하는 썸네일 사이즈에 따라, 메모리를 점유하는 크기가 달라지기 때문에 이 내용은 앱에서 처리하는 썸네일의 크기에 따라 달라진다.
우선, 썸네일이 점유하는 메모리의 크기를 살펴보면..
100 x 100의 썸네일인 경우, 100x100x4의 크기이니 40,000 byte의 메모리를 점유한다고 보면 되겠다. 그래서, 대략적으로 캐시 사이즈에 따른 메모리 사용량을 가늠해 보면..
100×100 썸네일을 메모리에 100개 올리게 되면, 4M 정도의 메모리를 점유하게 될 것이고.. 이 정보를 기준으로 캐시 사이즈를 정하면 되겠다..
위의, 정보를 기준으로 해서 디바이스가 허용하는 앱의 힙 정보를 살펴보면..
* 갤럭시 넥서스
07-24 11:51:04.377: E/CacheUtil(27521): dalvik.vm.heapstartsize : 8m
07-24 11:51:04.377: E/CacheUtil(27521): dalvik.vm.heapgrowthlimit : 96m <– 최대 힙 사이즈를 기준으로 캐시의 사이즈를 조절한다.
07-24 11:51:04.377: E/CacheUtil(27521): dalvik.vm.heapsize : 256m <– 전체 힙 사이즈
* 넥서스 10
07-24 12:02:46.003: E/CacheUtil(12619): dalvik.vm.heapstartsize : 16m
07-24 12:02:46.008: E/CacheUtil(12619): dalvik.vm.heapgrowthlimit : 192m <– 최대 힙 사이즈를 기준으로 캐시의 사이즈를 조절한다.
07-24 12:02:46.008: E/CacheUtil(12619): dalvik.vm.heapsize : 512m <– 전체 힙 사이즈
위의 정보를 바탕으로 캐시클래스를 만들어 보면..
import java.lang.reflect.Method; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.graphics.Bitmap; public class CacheUtil { static final String TAG = CacheUtil.class.getSimpleName(); static int THUMBNAIL_CACHE_COUNT = 100; static boolean DEBUG = true; static{ if(DEBUG) { Logger.e(TAG, "dalvik.vm.heapstartsize : " + get("dalvik.vm.heapstartsize")); Logger.e(TAG, "dalvik.vm.heapgrowthlimit : " + get("dalvik.vm.heapgrowthlimit")); Logger.e(TAG, "dalvik.vm.heapsize : " + get("dalvik.vm.heapsize")); Logger.e(TAG, "cache_size : " + getDynamicCacheSize()); } THUMBNAIL_CACHE_COUNT = getDynamicCacheSize(); } static LruCache<String, Bitmap> listCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT); public static LruCache<String, Bitmap> listCache() { if(listCache == null) listCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT); return listCache; } static LruCache<String, Bitmap> gridCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT); public static LruCache<String, Bitmap> gridCache() { if(gridCache == null) gridCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT); return gridCache; } static int getDynamicCacheSize() { String value = get("dalvik.vm.heapgrowthlimit"); if(StringUtil.isEmpty(value)) return THUMBNAIL_CACHE_COUNT; // M가 단위로 가져온다.. int size = extractInt(value); if(size <= 64) return 100; if(size <= 128) return 200; return 300; } private static String get(String key) { try { Class clazz = Class.forName("android.os.SystemProperties"); if (clazz == null) return ""; Method method = clazz.getDeclaredMethod("get", String.class); if (method == null) return ""; return (String) method.invoke(null, key); } catch (Exception e) { if (DEBUG) Logger.e(TAG, ExceptionUtil.exception(e)); } return ""; } private static int extractInt(String str) { Matcher matcher = Pattern.compile("\\d+").matcher(str); if (!matcher.find()) throw new NumberFormatException("For input string [" + str + "]"); return Integer.parseInt(matcher.group()); } }
위 클래스를 이용해서, 디바이스에 설정되어 있는 메모리 크기의 정보를 기준으로 메모리 캐시의 크기를 동적으로 설정할 수가 있겠다.