Vote22 앱에서 유튜브 영상의 썸네일 / 타이틀 / 영상 길이 등을 RecyclerView로 보여주는 Fragment에서 스크롤 시 굉장히 많은 버벅임이 있었습니다.
RecyclerView에서 스크롤 시 버벅임이 발생했던 이유:
임시 해결안 :
//In Adapter class
public void addItem(VideoData item) {
items.add(item);
if(item == null) return;
Thread mThread = new Thread() {
@Override
public void run() {
try {
URL url = new URL(item.getThumbnail());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
bitmaps.add(bitmap);
} catch (MalformedURLException e) {
e.printStackTrace();
bitmaps.add(null);
} catch (IOException e) {
e.printStackTrace();
bitmaps.add(null);
}
}
};
//thread 실행, 그 후 종료될 때 까지 메인 Thread는 기다린다
mThread.start();
try {
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
addItem 발생 시에 스레드에서 이미지 url을 통해 bitmap을 받아왔고, 이를 bitmaps에 넣어주었습니다.
참고 : https://bumptech.github.io/glide/int/recyclerview.html
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
VideoData item = items.get(position);
if(getItemViewType(position) == VIEW_TYPE_ITEM) {
VideoViewHolder viewHolder = (VideoViewHolder) holder;
Glide.with(viewHolder.itemView)
.load(item.getThumbnail())
.placeholder(R.color.light_gray)
.fallback(R.color.black)
.error(R.color.black)
.into(viewHolder.thumbNail);
viewHolder.setItem(item);
}
이처럼 Glide를 통해 정말 간편하게 recyclerview에 이미지 로딩을 적용할 수 있었습니다.
참조 :
Glide에 대해 더 찾아보던 중에 관련 유튜브 영상을 찾게 되어, 공부한 내용을 간단하게 정리해 보았습니다. 아래 Caching에 대한 내용은 첫번째 링크 영상의 내용이며, 두번째 링크의 영상은 glide 라이브러리 코드의 동작 과정을 빠르게 짚어주는데, 아직 저는 이해에 어려움을 겪고 있어서 추후에 정리하려고 합니다.
Glide cache는 memory cache + disk cache로 구성
Glide는 디폴트로 뷰에 맞게 이미지를 compress, convert 합니다.
Memory cache는 화면 회전 등의 상황에서 불필요하게 메모리의 데이터를 읽어오는 것을 방지합니다. cache를 통해 빠르게 대응하는 것이죠.
Disk Cache의 경우, 네트워크 등에서 이미 다운받아온 데이터를 불필요하게 다시 요청하는 것을 방지합니다.
Glide의 Memory cache에 사용되는 key는 굉장히 복잡한 방식으로 계산됩니다.
출처 : Glide github - Engine.java 파일
width, height, transformations등이 모두 key 계산에 반영됩니다. 유튜브 영상에 따르면, 같은 이미지를 2개의 이미지뷰에 로딩할 시, 그 key가 각각 다르다고 합니다.
즉, weakly reference된 것들은 GC가 실행되면 무조건 수거된다는 것(메모리 용량이 남았는지 여부에 관계 없이) 반대로 LRU cache는 strongly referenced되어 있어, GC 실행 시에 무조건 수거되지는 않습니다. 메모리 용량이 부족할 시에만 수거되는 것이죠.Weakly referenced objects have a shorter lifecycle because when the JVM performs garbage collection, once a weakly referenced object is found, it will be recycled (regardless of whether the memory is sufficient)
The pictures that are in use are cached by weak references, and the pictures that are not in use are cached by LRU Cache
사용중인 이미지는 weak reference로, 사용하지 않는 이미지는 LRU로 처리를 한다는 것.
Glide의 user는 weakly referenced cache는 끌 수 없지만, LRU cache는 끌 수 있습니다.
Reading the Memory Cache
Writing to Memory Cache
writes to the memory cache of the weak reference mechanism
writes to the memory cache of the LRU Cache Algorithm mechanism
when image is no longer used
전체 Step
Reading
Weak reference → Lru Cache → Disk Lru Cache → Network
Writing
reading의 반대