현재 이미지 동적 로딩 관련해서 작업을 하고 있는데 잘 안되네요
이미지 동적 로딩 및 캐쉬를 이용해서 저장을 하고 있어요.
현상 : 첫번째 동적 로딩을 할때 List 첫번째 목록 이미지가 자꾸 이상한 놈이 올라옴. (거의 5번째 이미지가 첫번째 목록에도 나타남.)
그 상태에서 다시 동적 로딩을 하면 캐쉬에 Hash-Map 형태로 저장되어서 첫번째 목록 이미지가 정상임.
추측 : 캐쉬에서 이미지를 가져올때는 Thread를 타지 않으나 첫번째 동적 로딩할때만 Thread를 타고 있음.
뭔가 구현이 잘못되었다고 생각함. 하지만 계속 삽질중~ㅜ.ㅜ
아래와 같이 구글링한 소스를 약간 수정해서 사용하고 있습니다.
1) ListAdapter의 getView
... 각 목록마다
final ImageView thumbNailView = viewCache.getThumbNailView();
BookEntity.asyncImageLoader.loadBitmap(bookEntity.imgUri, new ImageCallback() {
public void imageLoaded(Bitmap bm, String imageUrl) {
thumbNailView.setImageBitmap(bm);
}
}
});
2) asyncImageLoader.loadBitmap 함수 (위에서 호출한)
public Bitmap loadBitmap(final String imageUrl, final ImageCallback imageCallback) {
SoftReference<Bitmap> softReference = imageCache.get(imageUrl);
// 캐쉬에 이미 있다면 여기서 찾고 리턴됨.(아래 쓰레드 타지 않음.)
if(softReference != null){
Bitmap bm = (Bitmap)softReference.get();
if (bm != null) {
imageCallback.imageLoaded((Bitmap) bm, imageUrl);
return null;
}
}
// 요건 핸들러 쓰레드로부터 받은 비트맵과 URL를 전달함.
final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
imageCallback.imageLoaded(((ImageInfo) message.obj).bm, ((ImageInfo) message.obj).imageUrl);
}
};
// 요게 쓰레드. 조금 의심스럽지만 잘 모르겠음.
new Thread(new Runnable() {
@Override
public void run() {
ImageInfo imageInfo = new ImageInfo();
synchronized (imageInfo){
// Image Resizing (80 x 100) -- 이미지를 다운로드하고 downloadBitmap에서 받아서 사이즈 조정함.
Bitmap bm = Bitmap.createScaledBitmap(ConnectUtil.downloadBitmap(imageUrl), 80, 100, false);
imageCache.put(imageUrl, new SoftReference<Bitmap>(bm)); // 캐쉬에 담음.
imageInfo.bm = bm;
imageInfo.imageUrl = imageUrl;
}
Message message = handler.obtainMessage(0, imageInfo); //핸들러에 넘겨줌.
handler.sendMessage(message);
}
}).start();
return null;
}
public interface ImageCallback { // 인터페이스 공개.
public void imageLoaded(Bitmap bm, String imageUrl);
}
이게 꼬일 수 있는 지 조언 부탁드립니다.
(로딩 완료 후 쓰레드에 작업이 남아 있었는지 첫번째 이미지만 다시 뜨면서 이상한 이미지(5번째 이미지나 2번째 이미지)로 갑자기 바뀝니다.ㅜ.ㅜ)
View가 재활용되는 ListView의 특징 때문에 여러 스레드가 view를 경쟁적으로 순서 없이 점유하는 케이스가 나오게됩니다.
제가 쓰는 방법은 asyncTask를 만들되 그것도 position 별로 해시맵으로 관리 합니다.
getView에서는 이미지 해시맵과 asyncTask 해시맵을 보고 둘다 없으면 asyncTask 만들어서 해시맵 저장,
이미지 해시맵에 있으면 꺼내쓰기,
이미지 해시맵에는 없고 asyncTask 해시맵에만 있으면 그냥 패스...
asyncTask에서 로딩끝나면 해시맵에 담고 그걸 바로 뷰에 박지 마시고 notify...
이런 방식으로 하면 notify가 좀 많이 불리는감은 있는데 그래도 봐줄만한 정도입니다.
갤S는 열외 ㅠ.ㅠ