본문 바로가기
Lecture/Android

리스트뷰 외부이미지 삽입

by 알 수 없는 사용자 2012. 7. 15.
반응형

리스트뷰 내부에 외부이미지를 삽입하기위해서는 크게 두가지 방법을 사용합니다. 이 두가지에 대해 경험상 겪은 몇가지 고초와 노하우를 적어보겠습니다. 물론 코드까지 공유합니다.


1. 안드로이드OS의 웹캐싱 기능을 이용한 웹뷰방식

웹뷰방식은 말그대로 웹뷰를 배치하고 해당 뷰에 url을 적어 로드하는 방법입니다. 이 방법을 리스트뷰가 아닌 일반적인 이미지보여주기 용도로 사용한다면 매우 편리하고 간단합니다. 하지만 외부이미지의 사이즈가 변동적일경우에는 웹뷰의 크기에 잘 맞춰지지 않고 지 멋대로 보여질때가 흔합니다. 이때는 약간의 트릭을 사용하여 웹뷰의 크기에 최대한 이미지를 리사이징하는 방법이 있습니다.

public static String getImageHtmlCode(String _imageURL){

StringBuffer sb = new StringBuffer("<HTML>");

sb.append("<HEAD>");

sb.append("</HEAD>");

sb.append("<BODY>");

sb.append("<img width=\"100%\" src=\""+_imageURL +"\"/>");

sb.append("</BODY>");

sb.append("</HTML>");

return sb.toString();

}

이렇게 받아온 String을 웹뷰에 로드하는데 이때 사용하는 함수가

webViewResource.loadDataWithBaseURL(null, Tool.getImageHtmlCode(imageURL), "text/html", "utf-8", null);

가 되겠습니다. 파라미터는 2번째만 신경써주시고 나머지는 동일하게 주시면됩니다.


작성도중 혹시 핸들러처리가 필요하다고 생각하시는 분들이 계실텐데 웹뷰도 어면히 뷰이기때문에 자체적인 스레드로 url을 요청하게됩니다. 그러므로 따로 스레딩관리없이 간단하게 외부이미지를 가져와 사용할수 있습니다.


웹뷰는 사용하기도 편하고 간단한 장점이 있지만 그에따른 단점도 있습니다. 바로 웹뷰라는 이유만으로 스크롤링이 생길수가 있으며 웹에대해 터치이벤트를 따로 관리해줘야하기 떄문입니다. 통상 외부이미지를 보여주기만할 뿐인데 터치니 스크롤이니 하는 이유만으로 웹뷰를 사용하는데 여러가지 처리를 해줘야하는 이점이 있지만 몇가지 코드를 작성해주면 금방 해결됩니다.

setFocusable(false);

setBackgroundColor(0);

setHorizontalScrollBarEnabled(false);

setVerticalScrollBarEnabled(false);

setLongClickable(false);

setFocusableInTouchMode(false);

함수의 각 기능은 책이나 래퍼런스를 참고해도되고 영어로 읽어도 금방 이해할만한 수준의 함수들입니다.


단일 뷰에서의 웹뷰는 정말 이미지를 표현하기에 부족함이 없습니다. 하지만 최근들어 ics(안드로이드4.0)가 등장하면서 웹뷰를 이용하는 방식을 변경했는데 하드웨어적인 요소도 포함되어있다고 합니다. 

그래서 웹뷰를 사용하는 액티비티는 AndroidManifest.xml 에가서 <application> 내부에 android:hardwareAccelerated="true" 이 코드를 작성하여주면 깜빡임이 사라진다고합니다. (제가 ics가 아니라서 확인 불가...)


이제 웹뷰를 리스트뷰에 삽입하여 보여주는데 장점은 위에서 설명했고 단점은 리스트뷰내부에서 웹뷰를 사용할경우 웹뷰의 터치이벤트를 죽였으니 리스트중 웹뷰부분은 터치반응이 없습니다. 즉, 웹뷰를 제외한 나머지부분을 터치해야만 반응이 나온다는겁니다. 물론 프레임레이아웃으로 감싸도 되지만 이렇게 바보같은 짓을 할빠엔 차라리 이미지뷰캐싱방법을 더 선호합니다. 컴포넌트가 추가되면 될수록 리스트뷰의 가동성이 떨어지기 때문에 되도록이면 리스트뷰의 최적화를 위해 코딩해야합니다.


<리스트뷰 최적화 코딩기법 : http://blog.naver.com/PostView.nhn?blogId=dythmall&logNo=30095935698&parentCategoryNo=8&viewDate=&currentPage=1&listtype=0 >



■ 정리

장점 : 간단하고 약간의 함수적인요소를 더하면 정말 단일 이미지뷰로는 손색이 없다.

단점 : 리스트뷰에서 사용할경우 어쩔수없이 이벤터를 죽이는데 이때 웹뷰영역은 없는샘 쳐야한다. 즉, 웹뷰부분은 이벤트가 죽은 영역이다. 또한 ics버젼으로 업데이트되면서 조금더 손봐줄게 많다.




2. 개발자가 직접 외부 이미지를 디바이스에 캐싱하는 이미지뷰 방식

이 방식은 제가 직접 개발한건아니지만 대충 루틴은 이해하고있는 방식입니다. 웹뷰캐싱은 OS가 했다면 이 방식은 개발자가 직접 하는 방법입니다. 물론 4개의 클래스가 한패키지로 묶여있어 누구나 이용할수있으며 저도 앱에 적용하기가 무척 쉬웠습니다. 클래스 재활용이라는게 이런맛일까요 ㅇㅇ. 


패키지를 동봉하여 코드를 공유하겠습니다.

ImageCacheDemo.zip


소스는 열어보면 아시겠지만 4개의 클래스가 이미지를 비동기적으로 로드하고 리스트뷰는 getView함수에서 해당이미지를 비동기클래스의 생성자로 넘기면 알아서 이미지를 가져옵니다. 이떄 getView함수는 차일드의 카운트만큼 수행되거나 안드로이드 시스템에 의해 통제되어 모두 구성되지않고 일정 pool을 유지하면서 뷰를 구성하는데, 뷰를 구성하는 함수가 호출될때마다 이 비동기 함수가 호출되어 뷰는 뷰대로 이미지는 이미지대로 다운로드하여 뷰에 구성하므로써 성능의 향상을 얻을수 있으며 핵심적으로 WeakReference를 사용하여 핸들러보다 유연하게 UI를 제어하여 외부이미지 삽입하는데 강력한 이점이 있습니다. 


단일 이미지로드에서의 웹뷰와 비교할경우 저는 이미지를 보여주는 뷰는 역시 이미지뷰라는 생각에 이 방식이 좀더 올바르다고 생각합니다.


이미지를 가져오는 함수는 아래와 같습니다.

ImageRepository.INSTANCE.setImageBitmap(imageURL, ImageResource);


이 방법은 웹뷰와 달리 다른 설정이 필요없으며 항상 외부이미지가 이미지뷰의 크기에 최대로 설정됩니다. 물론 이미지사이즈가 세로로 길거나 가로로 길 경우에는 얘기가 달라지지만 웹뷰의 설정방식 없이 그냥 로드만할 경우 바로 최대화된 이미지를 볼 수 있습니다. 또한 터치에 따른 이벤트를 죽일 필요가 없기때문에 리스트뷰에서도 이미지뷰의 영역은 터치가 죽지않고 원하는 이벤트를 적용할 수 있습니다.


■ 정리

장점 : 웹뷰의 단점을 모두 커버한다.

단점 : ...흠.. 이미 클래스를 재활용하는 시점에서 단점은 잘모르겠고.. 나중에 빈틈이 보이면 추가하겠습니다.