[Android / Glide] Glide v4 적용

1. 시작하기

안드로이드 SDK 요구사항

  • 최소 SDK 버전 - Ice Cream Sandwich, 14 이상
  • 컴파일 SDK 버전 - Oreo MR1, 27 이상

권한

1
2
3
4
5
<uses-permission android:name="android.permission.INTERNET" />
// Glide가 연결 상태를 감시하고 실패한 요청을 재시작하는 것을 허용
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
// ExternalPreferredCacheDiskCacheFactory를 사용하여 Glide의 캐시를 공개 sdcard에 저장하기 위해
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

의존성

1
2
3
dependencies {
kapt 'com.github.bumptech.glide:glide:4.11.0' // 코틀린을 쓸 경우 kapt여야함.
}

2. 기본 형태

1
2
3
4
5
6
7
8
9
RequestOptions options = new RequestOptions()
.bitmapTransform(new RoundedCorners(20)) //radius
.placeholder(R.drawable.loading) // 이미지 로딩 중
.error(R.drawable.loading); // 이미지를 불러오지 못할 경우

Glide.with(context) // RequestManager 형태로 반환
.load("url"// RequestBuilder<Drawable> 형태로 반환 (이하 apply, into 동일하게 반환)
.apply(options)
.into(imageView);

ImageView의 setDrawableResource(resource)를 부르는 것으로 보임.

  • apply에 if문을 적용한 사례
    1
    2
    3
    4
    5
    6
    7
    8
    Glide.with(this)
    .load(url)
    .transition(DrawableTransitionOptions.withCrossFade(factory))
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .apply {
    if (corner = 0) transfoem(CenterInside(), RoundedCorners(corner.fromDpToPx()))
    }
    .into(this)

3. Glide 커스텀을 위한(=GlideApp 사용을 위한) AppGlideModule

Header에 User-Agent property 삽입

GlideApp 생성절차 링크를 따를 것.

4. 비트맵 관련 설정 - RequestOptions

(1) 주요 옵션

  • placeholder(resourceId): 이미지 로딩하는 중에 보여지는 대체 이미지.
  • error(resourceId): 이미지를 불러오지 못할 경우 대체 이미지.
  • skipMemoryCache(boolean): true 설정 시 캐시를 통하지 않고 이미지 로드.
  • override(int width, int height): target의 너비, 높이를 세팅. 이미지 리사이징.
  • centerCrop: default type. 외에 FitCenter, CircleCrop도 있음.

Glide에서 RequestOptions를 Glide.apply()했을 때와 안 했을 때의 이미지 transformation default 값이 다르다. (아래 예시: v4 공식문서 발췌)

→ RequestOptions을 적용하지 않았을 경우 default 값
Glide.with(context)
.load(url)
.fitCenter() // default
.into(imageView);

→ RequestOptions을 적용 시 default 값
Glide.with(context)
.load(url)
.apply(new RequestOptions().centerCrop())
.into(imageView);

→ xml에서 scaleType지정하면 그걸로 적용될 것 같은데, 만약 ImageView인데 scaleType을 지정하지 않았을 경우 AUIL와 Glide(RequestOptions적용한 것), Glide(RO 적용 안 한 것) 세 개의 작동이 다를 수 있음.

(2) 참고 옵션

  • diskCacheStrategy: 디스크 캐시 전략. 이미지 로드에 사용할 캐시 설정 ALL - DATA와 RESOURCE를 사용하여 원격 데이터를 캐시하고 RESOURCE만 사용하여 로컬 데이터를 캐싱 AUTO - defualt value. NONE - 디스크캐시 사용안함.
  • priority: 로드되는 이미지의 우선순위 결정 HIGH, IMMEDIATE, LOW, NORMAL
  • fallback: load할 url이 null일 경우 보여줄 대체 이미지. 이게 정의되어있지 않으면 error 이미지를, error 이미지도 없다면 placeholder 이미지로 대체됨.

(3) 예제. DisplayImageOptions와 대응되는 RequestOptions

1
2
3
4
5
6
7
8
9
private DisplayImageOptions mPlaceHolderOption = new DisplayImageOptions.Builder()
.resetViewBeforeLoading(true) // default
.cacheInMemory(true) // default
.cacheOnDisk(true) // default
.imageScaleType(ImageScaleType.EXACTLY) // default
.bitmapConfig(Bitmap.Config.RGB_565) // default
.showImageOnLoading(R.drawable.ic_loading) // loading place holder resource
.showImageOnFail(R.drawable.ic_loading) // failed place holder resource
.build();
  • resetViewBeforeLoading(true)
  • cacheInMemory(true) → RequestOptions.skipMemoryCache(false)
  • cacheOnDisk → RequestOptions.diskCacheStrategy
  • imageScaleType.EXACTLY: 뷰 사이즈에 맞춰서 이미지가 작아짐.
  • bitmapConfig → RequestOptions.format(DecodeFormat.PREFER_RGB_565)
      RequestOptions.format(DecodeFormat.PREFER_ARGB_8888)
    
    Glide’s default: RGB_565
  • showImageOnLoading / showImageOnFail → RequestOptions.placeholder(drawable) / RequestOptions.error(drawable)

5. Clear

(1) memory 캐시 삭제

1
2
// 이 메소드는 메인 스레드에서 호출되어야 한다.
Glide.get(context).clearMemory();

Glide의 캐시 메모리 영역과 BitmapPool을 정리한다.

단, 모든 메모리를 삭제하는 것은 특히 효율적이지 않으며 버벅거림과 로드 시간 증가를 방지하기 위해 가능한 한 피해야 한다.

(2) disk 캐시 삭제

1
2
3
4
5
6
7
8
val isMainThread = Looper.myLooper() == Looper.getMainLooper()
just<String>("")
  .subscribeOn(if (isMainThread) Schedulers.io() else Schedulers.immediate())
  .subscribe {
    // 이는 background 스레드에서 실행되어야 한다.
    Glide.get(this@SomethingActivity).clearDiskCache()
    Log.d("Deleted image memory cache and disk cache.")
}

디스크 캐시의 모든 항목을 지운다.

앱에서 실제로 테스트 해보니 캐시메모리의 디폴트 사이즈인 250MB를 채운 후 clearDiskCache()를 호출했을 때 변화는 다음과 같았다.

(Glide 외의 다른 캐시 데이터로 인해 왼쪽 before 사진에서는 250MB보다 약간 오버된 상태이다.)

6. 전환 - Transitions

1
2
3
4
5
6
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;

Glide.with(context)
.load(url)
.transition(withCrossFade()) // optional
.into(view);

Glide v4 does NOT apply a cross fade or any other transition by default.

Glide v4 부터는 어떤 transitions 이벤트도 기본값으로 들어가있지 않으므로 필요할 떄 추가할 수 있다. (v3에서는 기본값이 cross fade였음)

7. 리스너 - RequestListener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Glide.with(context)
.load(url)
.listener(new RequestListener<Drawable>() { // load() 다음에 추가할 것
        @Override
        boolean onLoadFailed(@Nullable GlideException e, Object model,
        Target<Drawable> target, boolean isFirstResource) {
        // 여기서 GlideException 로그 출력
        Log.e(TAG, "Load failed: " + e.printBlrBlr());
        return false; // Target에서 onLoadFailed가 호출되는 것을 허용한다.
        }
       
        /*
          resource: 로드된 이미지.
          model: 이미지를 로드하는 데 사용된 모델.
          dataSource: 이미지 출처. DATA_DISK_CACHE, LOCAL, MEMORY_CACHE, REMOTE와 같은 값.
        */
        @Override
        boolean onResourceReady(
        Drawable resource,
        Object model,
        Target<Drawable> target,
        DataSource dataSource,
        boolean isFirstResource) {
        // 성공 로그를 출력하거나 DataSource를 사용해 캐시적중을 추적할 수 있다.
        return false; // Target에서 onResourceReady가 호출되는 것을 허용한다.
        }
    })
    .into(imageView);

만약 Bitmap으로 로딩된 이미지를 얻고자 한다면,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Bitmap loadedImage = Glide.with(context)
.asBitmap()
.load(url)
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object o,
Target<Bitmap> target, boolean b) {
return false;
}

@Override
public boolean onResourceReady(**Bitmap bitmap**, Object o,
Target<Bitmap> target, DataSource dataSource, boolean b) {
image.setImage(ImageSource.bitmap(bitmap));
return false;
}
})
.submit(100100) // width, height: RequestBuilder API 참조
.get();

관련링크

Author

LEEJS

Posted on

2022-02-05

Updated on

2022-05-02

Licensed under

댓글