안드로이드 URL 이미지 캐싱
캐싱은 아니고 URL에서 가져온 이미지를 스토리지에 저장하고 ImageView에 보여주는거.
캐싱이라고 볼수도 있겠지. 생각하기 나름.
URL에서 이미지를 가져와서 리스트뷰에 넣을때 사용하기 위해서 만듬.
한번만 보여질 이미지라면 URL에서 Bitmap형태로 가져와 ImageView에 setImageBitmap() 하는것이 더 낳은듯.
하지만 xxx톡 같은 메신져의 경우, 친구목록에 사진은 바뀌어진 이미지만 다시 그려주고
같은 이미지인 경우 storage에서 가져와서 보여주는거 같다.
그래서 만들어봄.
먼저,
- cache경로에 이미지 파일이 있는 경우.
1. cache경로에서 이미지를 가져와 ImageView에 그린다.
2. url에서 이미지를 가져와 임시파일로 저장하고, cache경로에 이미지와 비교한다.
3.1. 두 파일이 같으면 임시파일을 삭제한다. 그리고 끝.
3.2. 두 파일이 다르면 url에서 가져온 이미지를 cache경로에 새로 저장하고,
ImageView에 새로운 이미지로 set해준다. 그리고 끝.
- cache경로에 이미지 파일이 없는 경우.
1. URL에서 이미지 가져와서 cache위치에 저장하고 ImageView에 그린다.
2. 끝.
간략하게.
저장되어있는 파일 먼저 화면에 보여주고, URL에서 가져온 이미지랑 비교해서
다르면 새로 저장하고 새로 화면에 보여줌.
리스트뷰에 적용해보니 리스트가 스크롤 될때 약간 버벅거리는듯하다.
아마도 이미지 크기를 줄이거나 임시파일을 쓰지않고 비교할수 있는 방법으로
고치면 좀 개선이 될거 같기도하다.
AndroidManifest.xml 에 권한을 줘야한다.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
public class ImageCacheDownloader extends AsyncTask<String, Integer, Bitmap> {
private Context context = null;
private ImageView imageview = null;
private String imageURL = null;
/**
* ImageCacheDownloader(Context _context, ImageView _imageView, String _url)
* @param _context
* @param _imageView
* @param _url
*/
public ImageCacheDownloader(Context _context, ImageView _imageView, String _url) {
this.context = _context;
this.imageview = _imageView;
this.imageURL = _url;
}
private String urlToFileFullPath(String _url) {
return context.getCacheDir().getAbsolutePath() + _url.substring(_url.lastIndexOf("/"), _url.length());
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
String fileFullPath = urlToFileFullPath(imageURL);
if( new File(fileFullPath).exists() ) {
//파일이 있으면. 저장되어있는 이미지 화면에 표시.
Bitmap myBitmap = BitmapFactory.decodeFile(fileFullPath);
imageview.setImageBitmap(myBitmap);
}
}
//@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
String fileFullPath = urlToFileFullPath(imageURL);
String tempFilePath = fileFullPath+"_temp";
writeFile(result, new File(tempFilePath)); // 다운로드한 파일 임시로 생성..
File downTempFile = new File(tempFilePath);
File newFile = new File(fileFullPath);
if( new File(fileFullPath).exists() ) {
//파일이 있으면.
Bitmap prevBitmap = BitmapFactory.decodeFile(fileFullPath);
Bitmap downBitmap = BitmapFactory.decodeFile(downTempFile.getAbsolutePath());
// 파일이 같다.
if( sameAs(prevBitmap,downBitmap) ) {
//Log.i("egg", "같은사진이다.");
} else {
//Log.i("egg", "다른 사진이라서 새로 설정한다");
imageview.setImageBitmap(result);
writeFile(result, newFile);
}
} else {
writeFile(result, newFile);
imageview.setImageBitmap(result);
}
downTempFile.delete();
}
/**
* Bitmap을 비교.
* @param bitmap1
* @param bitmap2
* @return boolean
*/
private boolean sameAs(Bitmap bitmap1, Bitmap bitmap2) {
ByteBuffer buffer1 = ByteBuffer.allocate(bitmap1.getHeight() * bitmap1.getRowBytes());
bitmap1.copyPixelsToBuffer(buffer1);
ByteBuffer buffer2 = ByteBuffer.allocate(bitmap2.getHeight() * bitmap2.getRowBytes());
bitmap2.copyPixelsToBuffer(buffer2);
return Arrays.equals(buffer1.array(), buffer2.array());
}
@Override
protected Bitmap doInBackground(String... params) {
return downloadBitmap(imageURL);
}
/**
* httpclient 이미지 파일 다운로드.
* @param imageUrl
* @return Bitmap
*/
private Bitmap downloadBitmap(String imageUrl) {
Bitmap bm = null;
HttpClient httpclient = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(imageUrl);
HttpResponse response;
try {
response = httpclient.execute(getRequest);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("egg", "Error " + statusCode + " while retrieving bitmap from " + imageUrl);
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
bm = bitmap;
//eturn bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (ClientProtocolException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
return bm;
}
/**
* 새로운 파일을 쓴다.
* @param Bimap bmp
* @param File f
*/
private void writeFile(Bitmap bmp, File f) {
FileOutputStream out = null;
try {
out = new FileOutputStream(f);
bmp.compress(Bitmap.CompressFormat.PNG, 50, out); // PNG type, 50
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception ex) {
}
}
}
}