Android 그림 3 급 캐 시 정책(네트워크,로 컬,메모리 캐 시)
현재 안 드 로 이 드 애플 리 케 이 션 에 서 는 그림 을 사용 할 수 밖 에 없습니다.그림 을 불 러 올 때마다 인터넷 에서 다시 끌 어 올 려 야 합 니 다.그러면 사용자 의 데 이 터 를 소모 할 뿐만 아니 라 그림 을 불 러 오 는 것 도 느 려 서 사용자 체험 이 좋 지 않 습 니 다.따라서 그림 캐 시 정책 을 사용 하 는 것 이 중요 합 니 다.일반적으로 안 드 로 이 드 응용 프로그램 에서 그림 의 캐 시 정책 은'메모리-로 컬-네트워크'3 급 캐 시 정책 을 사용 합 니 다.먼저 응용 프로그램 이 네트워크 에 접근 하여 그림 을 끌 어 옵 니 다.각각 로 컬 SD 카드 와 메모리 에 불 러 온 그림 을 저장 합 니 다.프로그램 이 다시 그림 을 불 러 올 필요 가 있 을 때 메모리 에 캐 시 가 있 는 지 여 부 를 판단 하고 있 으 면 메모리 에서 직접 끌 어 옵 니 다.그렇지 않 으 면 로 컬 SD 카드 에 캐 시가 있 는 지,SD 카드 에 캐 시가 존재 하면 그림 을 SD 카드 에서 끌 어 옵 니 다.그렇지 않 으 면 네트워크 에서 그림 을 불 러 옵 니 다.이 3 급 캐 시 시스템 에 따라 프로그램 이 그림 을 불 러 올 때 여 유 를 가지 고 메모리 가 넘 치지 않도록 할 수 있 습 니 다.
PS:물론 지금 인터넷 사진 을 처리 할 때 보통 사람들 은 XUtils 의 BitmapUtil 을 선택 합 니 다.인터넷 캐 시 를 잘 처리 해서 사용 하기에 매우 편리 합 니 다.본인 은 계속 사용 하고 있 습 니 다.BitMapUtil 의 실현 방향 을 본 떠 자신의 그림 로드 도 구 를 만 들 고 3 급 캐 시 전략 을 이해 하 며 자신 에 게 향상 되 기 를 바 랍 니 다.
네트워크 캐 시
네트워크 에서 그림 을 끌 어 내 는 것 은 엄 밀 히 말 하면 캐 시 라 고 할 수 없습니다.실질 적 으로 url 에 대응 하 는 그림 을 다운로드 하 는 것 입 니 다.여 기 는 캐 시 의 일종 으로 간주 합 니 다.BitmapUtil 의 display 방법 을 본 떠 서 제 가 직접 만 든 CustomBitmapUtils 도 이 방법 을 정의 합 니 다.들 어 오 는 url 에 따라 그림 을 ivPic 컨트롤 에 설정 합 니 다.
public void display(ImageView ivPic, String url) {
}
네트워크 캐 시 를 정의 하 는 도구 클래스 입 니 다.네트워크 에 접근 할 때 저 는 AsyncTask 를 사용 하여 이 루어 집 니 다.AsyncTask 의 doInBackGround 방법 에서 그림 을 다운로드 한 다음 에 그림 을 ivPic 컨트롤 에 설정 합 니 다.AsyncTask 는 세 개의 범 형 이 있 습 니 다.그 중에서 첫 번 째 범 형 은 비동기 작업 을 수행 할 때 execute 를 통 해 전 달 된 매개 변수 입 니 다.두 번 째 범 형 은 업데이트 진행 입 니 다.세 번 째 범 형 은 비동기 임 무 를 수행 한 후에 돌아 온 결과 입 니 다.우 리 는 비트 맵 을 되 돌려 줍 니 다.구체 적 인 다운로드 실현 코드 는 다음 과 같다.
/** * * * @author ZHY * */ public class NetCacheUtils
{ private LocalCacheUtils localCacheUtils;
private MemoryCacheUtils memoryCacheUtils;
public NetCacheUtils()
{
localCacheUtils = new LocalCacheUtils();
memoryCacheUtils = new MemoryCacheUtils();
}
/** * *
* @param ivPic *
@param url */
public void getBitmapFromNet(ImageView ivPic, String url)
{
// , MyAsyncTask task = new MyAsyncTask(); task.execute(ivPic, url); }
/** * -- , execute ;
-- ; --
* * @author ZHY * */
private class MyAsyncTask extends AsyncTask
{ private ImageView ivPic; private String url; //
--
@Override protected void onPreExecute()
{ super.onPreExecute();
}
//
@Override protected Bitmap doInBackground(Object... params)
{
// , URL ivPic = (ImageView) params[0]; url = (String) params[1]; Bitmap bitmap = downloadBitmap(url);
// ImageView URL , ImageView ivPic.setTag(url);
// ivPic URL return bitmap; }
// --
@Override protected void onProgressUpdate(Void... values)
{ super.onProgressUpdate(values);
}
// --
@Override protected void onPostExecute(Bitmap result)
{ String mCurrentUrl = (String) ivPic.getTag();
if (url.equals(mCurrentUrl))
{ ivPic.setImageBitmap(result);
System.out.println(" ");
// , SD ,
localCacheUtils.setBitmap2Local(url, result);
// , SD , memoryCacheUtils.setBitmap2Memory(url, result);
} } }
/** * *
* @param url * @return */
private Bitmap downloadBitmap(String url)
{
HttpURLConnection conn = null;
try
{
URL mURL = new URL(url);
// HttpURLConnection
conn = (HttpURLConnection) mURL.openConnection();
// conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setRequestMethod("GET");
// conn.connect();
// int code = conn.getResponseCode();
if (code == 200) {
// ,
InputStream is = conn.getInputStream();
// , , BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
// , ,
options.inPreferredConfig = Bitmap.Config.RGB_565;
//
// Bitmap bitmap = BitmapFactory.decodeStream(is); Bitmap bitmap = BitmapFactory.decodeStream(is, null, options)
;// return bitmap;
} }
catch (Exception e)
{ e.printStackTrace();
}
finally {
// conn.disconnect();
}
return null;
} }
로 컬 캐 시네트워크 에서 그림 을 불 러 온 후 로 컬 SD 카드 에 그림 을 저장 합 니 다.그림 을 불 러 올 때 SD 카드 에 그림 캐 시가 있 는 지 판단 하고 있 으 면 SD 카드 에서 그림 을 직접 불 러 옵 니 다.로 컬 캐 시 도구 류 에는 로 컬 SD 카드 에 네트워크 그림 을 설정 하여 SD 카드 의 그림 을 가 져 오 는 두 가지 공공 방법 이 있 습 니 다.그림 을 설정 할 때 키 쌍 으로 저장 하고,그림 의 url 을 키 로 하여 파일 의 이름,그림 의 Bitmap 를 비트 값 으로 저장 합 니 다.url 은 특수 문 자 를 포함 하고 있 기 때문에 그림 의 이름 으로 직접 저장 할 수 없 기 때문에 url 의 MD5 값 을 파일 의 이름 으로 사용 합 니 다.
/**
*
*
* @author ZHY
*
*/
public class LocalCacheUtils {
/**
*
*/
public static final String FILE_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath() + "/cache/pics";
/**
* SD ,key url MD5
*
* @param url
* @return
*/
public Bitmap getBitmapFromLocal(String url) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(FILE_PATH, fileName);
if (file.exists()) {
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
file));
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* SD
*
* @param url
* @param bitmap
*/
public void setBitmap2Local(String url, Bitmap bitmap) {
try {
//
String fileName = MD5Encoder.encode(url);
// , , fileName
File file = new File(FILE_PATH, fileName);
// file , File , , ,
File fileParent = file.getParentFile();
if (!fileParent.exists()) {
//
fileParent.mkdirs();//
}
//
bitmap.compress(CompressFormat.JPEG, 100,
new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
}
메모리 캐 시메모리 캐 시 는 메모리 에 그림 집합 을 저장 하 는 것 입 니 다.먼저 HashMap 이라는 키 값 이 맞 는 형식 으로 저장 되 고 url 을 key 로 하고 bitmap 를 value 로 합 니 다.그러나 자바 에 서 는 이러한 기본 new 대상 의 방식 이 강 인용 이 고 JVM 은 쓰레기 수 거 를 할 때 강 인용 을 회수 하지 않 기 때문에 불 러 온 그림 이 너무 많 으 면 map 가 점점 커지 고 OOM 이상 이 나타 나 기 쉽다.Android 2.3 이전 에는 소프트 인용 이나 약 인용 을 통 해 해결 할 수 있 었 지만,Android 2.3 이후 Google 은 더 이상 소프트 인용 을 추천 하지 않 았 습 니 다.Google 은 LruCache 를 사용 하 는 것 을 추 천 했 습 니 다.
과거 에 우 리 는 매우 유행 하 는 메모리 캐 시 기술 의 실현,즉 소프트 참조 또는 약 한 참조(SoftReference or WeakReference)를 자주 사용 했다.하지만 이 제 는 이런 방식 을 추천 하지 않 는 다.안 드 로 이 드 2.3(API Level 9)부터 쓰레기 수 거 기 는 소프트 인용 이나 약 한 인용 을 가 진 대상 을 회수 하 는 경향 이 강해 소프트 인용 과 약 한 인용 을 신뢰 할 수 없 게 만 들 기 때문이다.또한,Android 3.0(API Level 11)에 서 는 그림 의 데이터 가 로 컬 메모리 에 저장 되 기 때문에 예측 가능 한 방식 으로 방출 할 수 없습니다.이 는 잠재 적 인 위험 으로 인해 프로그램의 메모리 가 넘 치고 붕 괴 될 수 있 습 니 다.
LruCache 에 적당 한 캐 시 크기 를 선택 할 수 있 도록 다음 과 같은 여러 가지 요 소 를 고려 범위 에 넣 어야 합 니 다.예 를 들 어:
당신 의 장 치 는 모든 프로그램 에 얼마나 큰 메모 리 를 분배 할 수 있 습 니까?Android 기본 값 은 16M 입 니 다.장치 화면 에 최대 몇 장의 그림 이 표 시 됩 니까?화면 에 도 곧 표 시 될 수 있 기 때문에 미리 불 러 와 야 할 그림 이 얼마나 있 습 니까?장치 의 화면 크기 와 해상 도 는 각각 얼마 입 니까?초고 해상도 장치(예 를 들 어 갤 럭 시 넥 서 스)는 낮은 해상도 장치(예 를 들 어 넥 서 스 S)보다 같은 양의 그림 을 가지 고 있 을 때 더 큰 캐 시 공간 이 필요 합 니 다.그림 의 크기 와 크기,그리고 그림 마다 얼마나 많은 메모리 공간 을 차지 합 니까?그림 이 접근 하 는 빈 도 는 얼마나 됩 니까?일부 그림 의 접근 빈도 가 다른 그림 보다 높 지 않 습 니까?있 으 면 메모리 에 그림 을 상주 시 키 거나 여러 개의 LruCache 대상 을 사용 하여 다른 그룹의 그림 을 구분 해 야 할 수도 있 습 니 다.당신 은 수량 과 품질 간 의 균형 을 잘 유지 할 수 있 습 니까?어떤 때 는 낮은 픽 셀 의 그림 을 여러 개 저장 하고 배경 에서 스 레 드 를 열 어 높 은 픽 셀 의 그림 을 불 러 오 는 것 이 더욱 효과 적 입 니 다.이상 은 Google 이 LruCache 에 대한 설명 입 니 다.사실 LruCache 의 사용 은 매우 간단 합 니 다.Map 과 매우 가 깝 습 니 다.다만 LruCache 대상 을 만 들 때 최대 허용 메모 리 를 지정 해 야 합 니 다.일반적으로 현재 프로그램의 최대 실행 메모리 의 8 분 의 1 로 설정 하면 됩 니 다.
/**
*
*
* @author ZHY
*
*/
public class MemoryCacheUtils {
/*
* map , JVM map
*/
// private HashMap<string, bitmap=""> map = new HashMap<string, bitmap="">();
// , ,
// private HashMap<string, bitmap="">> mSoftReferenceMap = new
// HashMap<string, bitmap="">>();
// LruCache
private LruCache<string, bitmap=""> lruCache;
public MemoryCacheUtils() {
// lruCache Android ( Android 16 ) ( )
//
long mCurrentMemory = Runtime.getRuntime().maxMemory();
int maxSize = (int) (mCurrentMemory / 8);
// LruCache
lruCache = new LruCache<string, bitmap="">(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
//
// :
int byteCount = value.getRowBytes() * value.getHeight();//
return byteCount;
}
};
}
/**
* Bitmap
*
* @param url
* @return
*/
public Bitmap getBitmapFromMemory(String url) {
// Bitmap bitmap = map.get(url);
// SoftReference<bitmap> softReference = mSoftReferenceMap.get(url);
// Bitmap bitmap = softReference.get();
// Android2.3 ,Google lruCache
// LRU--least recently use
// , , ,
Bitmap bitmap = lruCache.get(url);
return bitmap;
}
/**
*
*
* @param url
* @param bitmap
*/
public void setBitmap2Memory(String url, Bitmap bitmap) {
// ,key,value , HashMap
// map.put(url, bitmap);
// map
// SoftReference<bitmap> mSoftReference = new
// SoftReference<bitmap>(bitmap);
// mSoftReferenceMap.put(url, mSoftReference);
lruCache.put(url, bitmap);
}
}</bitmap></bitmap></bitmap></string,></string,></string,></string,></string,></string,>
됐어.현재 3 급 캐 시 정책 패키지 가 완료 되 었 습 니 다.다음은 우리 만 의 BitmapUtils 를 맞 춥 니 다.
/**
* , Xutils BitmapUtil, , BitmapUtil, ,
* BitmapUtil CustomBitmapUtil
*
* @author ZHY
*
*/
public class CustomBitmapUtils {
private Bitmap bitmap;
private NetCacheUtils netCacheUtils;
private LocalCacheUtils localCacheUtils;
private MemoryCacheUtils memoryCacheUtils;
public CustomBitmapUtils() {
netCacheUtils = new NetCacheUtils();
localCacheUtils = new LocalCacheUtils();
memoryCacheUtils = new MemoryCacheUtils();
}
/**
* , URL ivPic
*
* @param ivPic
* ImageView
* @param url
*
*/
public void display(ImageView ivPic, String url) {
//
ivPic.setImageResource(R.drawable.ic_launcher);
// 1、
bitmap = memoryCacheUtils.getBitmapFromMemory(url);
if (bitmap != null) {
ivPic.setImageBitmap(bitmap);
System.out.println(" ");
return;
}
// 2、
bitmap = localCacheUtils.getBitmapFromLocal(url);
if (bitmap != null) {
ivPic.setImageBitmap(bitmap);
System.out.println(" SD ");
memoryCacheUtils.setBitmap2Memory(url, bitmap);//
return;
}
// 3、
netCacheUtils.getBitmapFromNet(ivPic, url);
/*
* , SD , , SD ,key URL MD5 ,
* value bitmap
*/
}
}
mainActivity 에서 ListView 를 사용 하여 네트워크 그림 을 불 러 옵 니 다.
/**
* Android -- - -
*
* @author ZHY
*
*/
public class MainActivity extends Activity {
private ListView list;
private Button btn;
private CustomBitmapUtils utils;
private static final String BASE_URL = "http://192.168.0.148:8080/pics";
//
String[] urls = { BASE_URL + "/1.jpg", BASE_URL + "/2.jpg",
BASE_URL + "/3.jpg", BASE_URL + "/4.jpg", BASE_URL + "/5.jpg",
BASE_URL + "/6.jpg", BASE_URL + "/7.jpg", BASE_URL + "/8.jpg",
BASE_URL + "/9.jpg", BASE_URL + "/10.jpg", BASE_URL + "/11.jpg",
BASE_URL + "/12.jpg", BASE_URL + "/13.jpg", BASE_URL + "/14.jpg",
BASE_URL + "/15.jpg", BASE_URL + "/16.jpg", BASE_URL + "/17.jpg",
BASE_URL + "/18.jpg", BASE_URL + "/19.jpg", BASE_URL + "/20.jpg",
BASE_URL + "/21.jpg", BASE_URL + "/22.jpg", BASE_URL + "/23.jpg",
BASE_URL + "/24.jpg", BASE_URL + "/25.jpg", BASE_URL + "/26.jpg",
BASE_URL + "/27.jpg", BASE_URL + "/28.jpg", BASE_URL + "/29.jpg",
BASE_URL + "/30.jpg" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = (ListView) findViewById(R.id.list);
btn = (Button) findViewById(R.id.btn_load);
utils = new CustomBitmapUtils();
//
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MyAdapter adapter = new MyAdapter();
list.setAdapter(adapter);
}
});
}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return urls.length;
}
@Override
public String getItem(int position) {
return urls[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(MainActivity.this,
R.layout.item_list, null);
holder = new ViewHolder();
holder.ivPic = (ImageView) convertView.findViewById(R.id.iv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
utils.display(holder.ivPic, urls[position]);
return convertView;
}
class ViewHolder {
ImageView ivPic;
}
}
}
실행 결 과 는 다음 과 같 습 니 다.프로그램 이 처음 실행 되 었 습 니 다.로 그 는 다음 과 같이 인쇄 되 었 습 니 다.
이후 SD 카드 에 그림 캐 시 를 하고 로 컬 에서 그림 을 불 러 옵 니 다.
그리고 그림 을 메모리 에 캐 시 하여 메모리 에서 그림 을 불 러 옵 니 다.
OK,지금까지 안 드 로 이 드 에 있 는 그림 의 3 급 캐 시 원 리 를 모두 소 개 했 습 니 다.저 자신 은 많은 이익 을 얻 었 습 니 다.필요 한 친 구 를 도 울 수 있 기 를 바 랍 니 다.원본 코드 가 필요 한 경우 아래 링크 를 클릭 하여 다운로드 하 십시오.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.