android DiskLruCache 분석, 하 드 디스크 캐 시
9841 단어 androidoomDiskLruCache
작가 님 께 서 공유 해 주 셔 서 감사합니다.
알다 시 피 LruCache 기술 은 다 중 그림 OOM 을 방지 하 는 핵심 적 인 해결 방향 이지 만 LruCache 는 메모리 에 있 는 그림 의 저장 과 방출 만 관 리 했 을 뿐 메모리 에서 그림 이 제거 되면 네트워크 에서 그림 을 다시 불 러 와 야 하 는데 시간 이 많이 걸 릴 것 이다.이에 구 글 은 또 하나의 하 드 디스크 캐 시 솔 루 션 을 제공 했다. DiskLruCache (구 글 공식 작성 은 아니 지만 공식 인증 을 받 았 다).
1, 캐 시 위치:
DiskLruCache 는 데이터 의 캐 시 위 치 를 제한 하지 않 고 자 유 롭 게 설정 할 수 있 지만, 일반적으로 대부분의 프로그램 은 캐 시 위 치 를 / sdcard / android / data / < application package > / cache 라 는 경로 로 선택 합 니 다.이 위치 에서 선택 하 는 것 은 두 가지 장점 이 있다. 첫째, 이것 은 SD 카드 에 저 장 된 것 이기 때문에 아무리 많은 데 이 터 를 캐 시 하 더 라 도 휴대 전화의 내장 저장 공간 에 영향 을 주지 않 고 SD 카드 공간 만 충분 하면 된다.둘째, 이 경 로 는 안 드 로 이 드 시스템 에 의 해 프로그램의 캐 시 경로 로 인 정 됩 니 다. 프로그램 이 마 운 트 해제 되 었 을 때 이곳 의 데이터 도 함께 삭 제 됩 니 다. 그러면 프로그램 을 삭제 한 후에 핸드폰 에 남아 있 는 데이터 에 문제 가 발생 하지 않 습 니 다.
경로 아래 bitmap 폴 더 아래 journal 이라는 파일 이 있 습 니 다. journal 파일 은 DiskLruCache 의 로그 파일 입 니 다. 프로그램 은 모든 그림 에 대한 작업 기록 을 이 파일 에 저장 합 니 다. journal 이라는 파일 을 보면 프로그램 이 DiskLruCache 기술 을 사용 한 다 는 것 을 상징 합 니 다.비트 맵 의 긴 파일 이름 이 캐 시 된 그림 입 니 다.
2, 코드 사용:
(1) 먼저, DiskLRuCache 는 new 에서 인 스 턴 스 를 낼 수 없다 는 것 을 알 아야 합 니 다. 만약 에 우리 가 DiskLRuCache 의 인 스 턴 스 를 만 들 려 면 open () 방법 을 호출 해 야 합 니 다. 인 터 페 이 스 는 다음 과 같 습 니 다.
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
첫 번 째 매개 변 수 는 데이터 의 캐 시 주 소 를 지정 합 니 다. 두 번 째 매개 변 수 는 현재 프로그램의 버 전 번 호 를 지정 합 니 다. 세 번 째 매개 변 수 는 같은 key 가 몇 개의 캐 시 파일 에 대응 할 수 있 는 지 지정 합 니 다. 기본적으로 1 을 전달 하고 네 번 째 매개 변 수 는 최대 몇 바이트 의 데 이 터 를 캐 시 할 수 있 는 지 지정 합 니 다.
SD 가 마침 제거 되 는 것 을 방지 하기 위해 서 우 리 는 코드 를 써 서 캐 시 주 소 를 가 져 옵 니 다.
public File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + uniqueName);
}
SD 카드 가 존재 하거나 SD 카드 가 제거 되 지 않 을 때 getExternalCacheDir () 방법 으로 캐 시 경 로 를 가 져 옵 니 다. 그렇지 않 으 면 getCacheDir () 방법 으로 캐 시 경 로 를 가 져 옵 니 다.전 자 는 / sdcard / android / data / < application package > / cache 경 로 를 얻 었 고 후 자 는 / data / data / < application package > / cache 경 로 를 얻 었 습 니 다.유 니 크 Name: 캐 시 폴 더 이름 입 니 다.
응용 버 전 번호 가 져 오기:
public int getAppVersion(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 1;
}
설명: 버 전 번호 가 바 뀔 때마다 캐 시 경로 에 저 장 된 모든 데 이 터 는 삭 제 됩 니 다. DiskLruCache 는 프로그램 이 버 전 업데이트 가 있 을 때 모든 데 이 터 를 인터넷 에서 다시 가 져 와 야 한다 고 생각 하기 때 문 입 니 다.
so, open 방법:
DiskLruCache mDiskLruCache = null;
try {
File cacheDir = getDiskCacheDir(context, "bitmap");
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
} catch (IOException e) {
e.printStackTrace();
}
먼저 getDiskCacheDir () 방법 을 호출 하여 캐 시 주소 의 경 로 를 가 져 온 다음 이 경로 가 존재 하 는 지 판단 하고 존재 하지 않 으 면 만 듭 니 다.이 어 DiskLruCache 의 open () 방법 을 호출 하여 인 스 턴 스 를 만 들 고 네 개의 인 자 를 입력 하면 됩 니 다.
DiskLruCache 의 인 스 턴 스 가 있 으 면 우 리 는 캐 시 된 데 이 터 를 조작 할 수 있 습 니 다. 작업 유형 은 주로 기록, 접근, 제거 등 을 포함 합 니 다.
(2) 네트워크 URL 그림 을 로 컬 캐 시 에 기록 합 니 다.
쓰 는 동작 은 DiskLruCache. Editor 같은 종 류 를 통 해 이 루어 집 니 다.이와 유사 하 게 이 클래스 도 new 가 될 수 없습니다. DiskLruCache 의 edit () 방법 으로 인 스 턴 스 를 가 져 와 야 합 니 다.
public Editor edit(String key) throws IOException
key 는 캐 시 파일 의 파일 이름 이 되 고 그림 의 URL 과 일일이 대응 해 야 합 니 다. 그림 URL 에 특수 문자 가 포함 되 어 있 을 수 있 기 때문에 이 문자 들 은 파일 이름 을 지 을 때 비합법적일 수 있 습 니 다.사실 가장 쉬 운 방법 은 그림 의 URL 을 MD5 인 코딩 하 는 것 입 니 다. 인 코딩 된 문자열 은 유일한 것 이 고 0 - F 와 같은 문자 만 포함 되 어 파일 의 이름 규칙 에 완전히 부합 합 니 다.
public String hashKeyForDisk(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 String bytesToHexString(byte[] bytes) {
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();
}
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
DiskLruCache. Editor 의 인 스 턴 스 가 있 으 면 new Output Stream () 방법 으로 출력 흐름 을 만 든 다음 downloadUrlToStream () 에 전송 하면 캐 시 를 다운로드 하고 기록 하 는 기능 을 수행 할 수 있 습 니 다.new OutputStream () 방법 에 주의 하여 index 인 자 를 받 습 니 다. 앞에서 value Count 를 설정 할 때 1 을 지정 하기 때문에 여기 index 에서 0 을 전달 하면 됩 니 다.기록 작업 이 실 행 된 후에 우 리 는 commt () 방법 을 호출 하여 제출 해 야 기록 이 유효 하 며, abort () 방법 을 호출 하면 이번 기록 을 포기 하 는 것 을 표시 합 니 다.
new Thread(new Runnable() {
@Override
public void run() {
try {
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
if (downloadUrlToStream(imageUrl, outputStream)) {
editor.commit();
} else {
editor.abort();
}
}
// ,
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
out = new BufferedOutputStream(outputStream, 8 * 1024);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}
return false;
}
(3) 캐 시 읽 기:
public synchronized Snapshot get(String key) throws IOException
get () 방법 은 key 를 입력 하여 해당 하 는 캐 시 데 이 터 를 가 져 오 라 고 요구 합 니 다. 이 key 는 그림 URL 을 MD5 인 코딩 한 값 임 에 틀림없다.
여기 서 얻 은 것 은 DiskLruCache. snapshot 대상 입 니 다. getInputStream () 방법 을 호출 하면 캐 시 파일 의 입력 흐름 을 얻 을 수 있 습 니 다. 마찬가지 로 getInputStream () 방법 도 index 인 자 를 전달 해 야 합 니 다. 여기 서 0 을 입력 하면 됩 니 다.캐 시 를 완전히 읽 고 그림 을 인터페이스 에 불 러 오 는 코드 는 다음 과 같 습 니 다.
try {
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
if (snapShot != null) {
InputStream is = snapShot.getInputStream(0);
Bitmap bitmap = BitmapFactory.decodeStream(is);
mImage.setImageBitmap(bitmap);
}
} catch (IOException e) {
e.printStackTrace();
}
(4) 캐 시 삭제:
public synchronized boolean remove(String key) throws IOException
설명: 이 방법 은 우리 가 자주 그것 을 호출 해 서 는 안 된다.캐 시 된 데이터 가 너무 많아 서 SD 카드 의 공간 을 너무 많이 차지 하 는 문 제 를 전혀 걱정 할 필요 가 없 기 때문에 DiskLruCache 는 우리 가 open () 방법 을 호출 할 때 설정 한 캐 시 최대 값 에 따라 불필요 한 캐 시 를 자동 으로 삭제 합 니 다.키 에 대응 하 는 캐 시 내용 이 만 료 되 었 는 지 확인 해 야 합 니 다. 네트워크 에서 최신 데 이 터 를 가 져 올 때 만 reove () 방법 으로 캐 시 를 제거 해 야 합 니 다.
(5) 기타 API:
1. size()
이 방법 은 현재 캐 시 경로 에서 모든 캐 시 데이터 의 총 바이트 수 를 되 돌려 줍 니 다. byte 단위 로 프로그램 에서 현재 캐 시 데이터 의 총 크기 를 인터페이스 에 표시 해 야 한다 면 이 방법 으로 계산 할 수 있 습 니 다.
2.flush()
이 방법 은 메모리 의 조작 기록 을 로그 파일 (즉 journal 파일) 에 동기 화 하 는 데 사 용 됩 니 다.이 방법 은 매우 중요 하 다. 왜냐하면 DiskLruCache 가 정상적으로 일 할 수 있 는 전 제 는 journal 파일 의 내용 에 의존 해 야 하기 때문이다.앞에서 캐 시 쓰기 동작 을 설명 할 때 저 는 이 방법 을 한 번 호출 한 적 이 있 습 니 다. 그러나 캐 시 를 쓸 때마다 flush () 방법 을 호출 하 는 것 이 아 닙 니 다. 자주 호출 하 는 것 은 좋 은 점 이 없고 journal 파일 을 동기 화 하 는 시간 만 추가 할 수 있 습 니 다.비교적 표준적 인 방법 은 Activity 의 onPause () 방법 에서 flush () 방법 을 한 번 호출 하면 된다.
3.close()
이 방법 은 DiskLruCache 를 닫 는 데 사 용 됩 니 다. open () 방법 과 대응 하 는 방법 입 니 다.닫 으 면 DiskLruCache 에서 캐 시 데 이 터 를 조작 하 는 방법 을 더 이상 호출 할 수 없습니다. 보통 Activity 의 onDestroy () 방법 에서 close () 방법 만 호출 해 야 합 니 다.
4.delete()
이 방법 은 모든 캐 시 데 이 터 를 삭제 하 는 데 사 용 됩 니 다. 예 를 들 어 캐 시 기능 을 수 동 으로 청소 하 는 것 은 사실 DiskLruCache 의 delete () 방법 만 호출 하면 가능 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.