LRU 알고리즘 캐 시 그림 사용 하기
이 컨트롤 들 중 하위 컨트롤 이 표시 되 지 않 을 때 시스템 은 메모리 소 모 를 줄 이기 위해 이 컨트롤 을 다시 사용 합 니 다.또한 쓰레기 수 거 체 제 는 메모리 에 불 러 온 Bitmap 자원 도 방출 합 니 다.일반적으로 이것 은 모두 좋 은 것 이지 만 사용자 가 화면 을 왔다갔다 할 때 UI 의 유창 성과 그림 을 불 러 오 는 효율 을 확보 하기 위해 서 는 표시 할 그림 을 반복 적 으로 처리 하 는 것 을 피해 야 합 니 다.메모리 캐 시 와 디스크 캐 시 를 사용 하면 이 문 제 를 해결 할 수 있 습 니 다.캐 시 를 사용 하면 컨트롤 이 처 리 된 그림 을 빠르게 불 러 올 수 있 습 니 다.
이 절 은 UI 의 불 러 오기 입력 과 미끄럼 의 유창 성 을 높이 기 위해 캐 시 를 사용 하 는 방법 을 소개 합 니 다.
메모리 캐 시 사용
메모리 캐 시 는 그림 에 접근 하 는 속 도 를 높 였 지만 많은 메모 리 를 사용 해 야 합 니 다.LruCache 클래스(API 4 이전에 Support Library 의 클래스 를 사용 할 수 있 음)는 Bitmap 캐 시 에 특히 적합 하 며,최근 사용 한 Bitmap 대상 을 강 인용 으로 저장(LinkedHashMap 에 저장)하고,캐 시 수량 이 예 정 된 값 에 도달 하면 자주 사용 하지 않 는 이미 지 를 삭제 합 니 다.
메모:과거 에는 메모리 캐 시 를 실현 하 는 데 자주 사용 되 었 던 방법 은 SoftReference 나 WeakReference bitmap 캐 시 를 사 용 했 지만 이런 방식 을 사용 하 는 것 을 추천 하지 않 습 니 다.안 드 로 이 드 2.3(API Level 9)부터 쓰레기 수 거 를 시작 으로 soft/weak 인용 을 강제로 회수 하여 이 캐 시 들 이 효율 적 으로 향상 되 지 않 았 습 니 다.또 안 드 로 이 드 3.0(API Level 11)이전 에는 이 캐 시 된 비트 맵 데 이 터 를 바 텀 메모리(native memory)에 저장 하고,예 정 된 조건 에 도달 해도 이 대상 을 방출 하지 않 아 프로그램 이 메모리 제한 을 초과 해 붕괴 할 수 있다.
LruCache 를 사용 할 때 다음 과 같은 요 소 를 고려 하여 적당 한 캐 시 수량 인 자 를 선택해 야 합 니 다.
모든 프로그램 에 적합 한 만능 레 시 피 가 없습니다.사용 상황 을 분석 하고 캐 시 정책 을 지정 해 야 합 니 다.너무 작은 캐 시 를 사용 하 는 것 은 효과 가 없 으 며,너무 큰 캐 시 를 사용 하면 더 많은 메모리 가 소모 되 어 자바.lang.OutOf Memory 가 이상 하거나 프로그램의 다른 기능 을 사용 할 수 있 는 메모리 가 적 게 남 을 수 있 습 니 다.
다음은 LruCache 캐 시 를 사용 하 는 예제 입 니 다.
private LruCache<string, bitmap=""> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((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;
mMemoryCache = 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.
return bitmap.getByteCount();
}
};
...
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
메모:이 예제 에서 이 프로그램의 8 분 의 1 메모리 가 캐 시 용 으로 사용 되 었 습 니 다.normal/hdpi 장치 에 서 는 최소 4MB(32/8)메모리 가 있 습 니 다.해상도 800×480 의 장치 에서 전체 화면 에 있 는 GridView 가 그림 을 모두 채 우 면 1.5MB(800*480*4 bytes)차이 가 나 지 않 는 메모 리 를 사용 하기 때문에 메모리 에 2.5 페이지 의 그림 을 캐 시 한 것 이 많 지 않다.
ImageView 에 그림 이 표 시 될 때 는 LruCache 에 존재 하 는 지 확인 합 니 다.존재 하면 캐 시 된 그림 을 사용 합 니 다.존재 하지 않 으 면 배경 스 레 드 를 시작 하여 그림 을 불 러 오고 캐 시 합 니 다.
public void loadBitmap(int resId, ImageView imageView) {
final String imageKey = String.valueOf(resId);
final Bitmap bitmap = getBitmapFromMemCache(imageKey);
if (bitmap != null) {
mImageView.setImageBitmap(bitmap);
} else {
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
task.execute(resId);
}
}
BitmapWorkerTask 는 새 그림 을 캐 시 에 추가 해 야 합 니 다:
class BitmapWorkerTask extends AsyncTask<integer, void,="" bitmap=""> {
...
// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
final Bitmap bitmap = decodeSampledBitmapFromResource(
getResources(), params[0], 100, 100));
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
...
}
디스크 캐 시 사용
최근 에 사용 한 그림 에 접근 할 때 메모리 캐 시 속도 가 빠 르 지만 캐 시 에 그림 이 있 는 지 확인 할 수 없습니다.GridView 와 같은 컨트롤 은 표시 해 야 할 그림 이 많 을 수 있 으 며,곧 그림 데이터 가 캐 시 용량 을 채 울 수 있 습 니 다.또한 프로그램 이 다른 작업 에 의 해 중 단 될 수도 있 습 니 다.예 를 들 어 전 화 를 걸 었 을 때 프로그램 이 배경 에 있 을 때 시스템 은 이 그림 캐 시 를 알 수 있 습 니 다.사용자 가 프로그램 을 다시 사용 하려 면 이 그림 들 을 다시 처리 해 야 합 니 다.
이 경우 처리 한 그림 을 디스크 캐 시 로 저장 할 수 있 습 니 다.메모리 캐 시 에서 사용 할 수 없 을 때 디스크 캐 시 에서 불 러 와 그림 처리 과정 을 생략 할 수 있 습 니 다.물론 디스크 에서 그림 을 불 러 오 는 것 이 메모리 에서 읽 는 것 보다 훨씬 느 리 고 비 UI 스 레 드 에서 디스크 그림 을 불 러 와 야 합 니 다.
메모:캐 시 된 그림 이 자주 사용 된다 면 ContentProvider 를 사용 하 는 것 을 고려 할 수 있 습 니 다.예 를 들 어 갤러리 프로그램 에서 이렇게 마 르 는 것 입 니 다.
예제 코드 에 간단 한 DiskLruCache 가 있 습 니 다.그리고 Android 4.0 에는 더 신뢰 할 수 있 고 추천 할 수 있 는 DiskLruCache(libcore/luni/src/main/java/libcore/io/diskLruCache.java)가 포함 되 어 있 습 니 다.이것 을 4.0 이전 버 전에 쉽게 이식 할 수 있 습 니 다(href="http://www.google.com/search?q=disklrucache">구 글 은 다른 사람들 이 이미 이렇게 했 는 지 확인 해 보 세 요!)
이것 은 업 데 이 트 된 버 전의 DiskLruCache 입 니 다.
private DiskLruCache mDiskCache;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final String DISK_CACHE_SUBDIR = "thumbnails";
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Initialize memory cache
...
File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR);
mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE);
...
}
class BitmapWorkerTask extends AsyncTask<integer, void,="" bitmap=""> {
...
// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
final String imageKey = String.valueOf(params[0]);
// Check disk cache in background thread
Bitmap bitmap = getBitmapFromDiskCache(imageKey);
if (bitmap == null) { // Not found in disk cache
// Process as normal
final Bitmap bitmap = decodeSampledBitmapFromResource(
getResources(), params[0], 100, 100));
}
// Add final bitmap to caches
addBitmapToCache(String.valueOf(imageKey, bitmap);
return bitmap;
}
...
}
public void addBitmapToCache(String key, Bitmap bitmap) {
// Add to memory cache as before
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
// Also add to disk cache
if (!mDiskCache.containsKey(key)) {
mDiskCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromDiskCache(String key) {
return mDiskCache.get(key);
}
// Creates a unique subdirectory of the designated app cache directory. Tries to use external
// but if not mounted, falls back on internal storage.
public static File getCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
|| !Environment.isExternalStorageRemovable() ?
context.getExternalCacheDir().getPath() : context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
UI 스 레 드 에서 메모리 캐 시 를 감지 하고 배경 스 레 드 에서 디스크 캐 시 를 감지 합 니 다.UI 스 레 드 에서 디스크 작업 이 이 루어 져 서 는 안 됩 니 다.그림 처리 가 끝나 면 나중에 사용 할 수 있 도록 메모리 캐 시 와 디스크 캐 시 에 최종 결 과 를 동시에 추가 합 니 다.
설정 변경 이벤트 처리
실행 중인 설정 변경-예 를 들 어 화면 방향 변경-실행 중인 Activity 를 Android 가 파괴 한 다음 새 설정 을 사용 하여 이 Activity 를 시작 합 니 다(자세 한 내용 은 여기 Handling Runtime Changes 참조).설정 이 바 뀌 었 을 때 모든 그림 을 다시 처리 하지 않도록 주의 하여 사용자 체험 을 향상 시 켜 야 합 니 다.
다행히도 메모리 캐 시 부분 에 좋 은 그림 캐 시가 있 습 니 다.이 캐 시 는 Fragment(Fragment 는 setRetainInstance(true)함수 로 저 장 됩 니 다)를 통 해 새로운 Activity 에 전달 할 수 있 습 니 다.Activity 가 다시 시작 되면 Fragment 는 Activity 에 다시 추 가 됩 니 다.이 Fragment 를 통 해 캐 시 대상 을 가 져 올 수 있 습 니 다.
다음은 Fragment 에 캐 시 를 저장 하 는 예제 입 니 다.
private LruCache<string, bitmap=""> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
RetainFragment mRetainFragment =
RetainFragment.findOrCreateRetainFragment(getFragmentManager());
mMemoryCache = RetainFragment.mRetainedCache;
if (mMemoryCache == null) {
mMemoryCache = new LruCache<string, bitmap="">(cacheSize) {
... // Initialize cache here as usual
}
mRetainFragment.mRetainedCache = mMemoryCache;
}
...
}
class RetainFragment extends Fragment {
private static final String TAG = "RetainFragment";
public LruCache<string, bitmap=""> mRetainedCache;
public RetainFragment() {}
public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
if (fragment == null) {
fragment = new RetainFragment();
}
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
<strong>setRetainInstance(true);</strong>
}
}
Fragment 를 사용 하지 않 고 장치 의 화면 방향 을 회전 시 켜 구체 적 인 그림 불 러 오 는 상황 을 볼 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【Codility Lesson3】FrogJmpA small frog wants to get to the other side of the road. The frog is currently located at position X and wants to get to...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.