- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
- rxjava
- 안드로이드
- 책리뷰
- Kotlin
- 책추천
- jlpt
- PR
- 코틀린
- ai
- 일본어기초
- 진짜일본어
- suspend
- KotlinInAction
- errorhandling
- coroutine
- CustomTab
- github
- pullrequest
- 인공지능
- 진짜학습지
- 진짜학습지후기
- posting
- 일본어문법
- Android
- n3문법
- androidstudio
- blog
- 학습지
- GIT
- webflux
코딩하는 개굴이
[안드로이드] Coil 라이브러리로 이미지 로딩하기 본문
Picasso 를 사용하다가 Coil 라이브러리로 마이그레이션을 하기로 함에 따라
Coil 의 사용법 및 에러 핸들링 관련하여 포스팅을 해보려한다.
Coil 이란?
coil 은 Kotlin Coroutin 으로 만들어진 Android 백엔드 이미지 로딩 라이브러리이다.
coil 외에 url 및 File path 등의 이미지를 로딩하기 위한 라이브러리는 Picasso, Glide 등 다수 존재하지만, 본인은 Coil 을 적용해보려한다.
Migration 및 적용하기
implementation("io.coil-kt:coil:2.2.2")
implementation("io.coil-kt:coil-gif:2.2.2") //coil 에서 gif 적용을 위한 implementation 으로 선택사항
기존의 31 이었던 targetSdkVersion 을 32 이상으로 올려야했다.
이렇게 세팅했다면, 적용하는 부분은 아래와 같이 간단하다.
// URL
imageView.load("<https://www.example.com/image.jpg>")
// File
imageView.load(File("/path/to/image.jpg"))
그러나, 경우에 따라 place holder 를 필요로 하거나, bitmap 을 불러와야하는 경우 등 load() 만으로 구현이 되지 않는 경우들이 존재할 수 있다.
그럴 경우, 아래와 같이 imageLoader 와 imageRequest 를 사용해 구현되어야한다.
//Picasso
//bitmap 을 가져오는 형태
sampleBitmap = Picasso.get()
.load(Uri.parse(uriString))
.resize(DEFINED_SIGNATURE_WIDTH, DEFINED_SIGNATURE_HEIGHT)
.get()
//Coil
//bitmap 을 가져오는 형태
//imageLoader 는 singleton 으로 선언되어있다
val imageRequest = ImageRequest.Builder(getApplication<Application>().applicationContext)
.data(uriString)
.allowHardware(false) //하위 에러 핸들링을 위한 옵셔널 세팅
.build()
val bitmap = imageLoader.execute(imageRequest).drawable?.toBitmap()
ImageLoader
single {
ImageLoader.Builder(androidApplication())
.components { //gif 디코더 등록을 위한 코드로 생략 가능
if (Build.VERSION.SDK_INT >= 28) {
add(ImageDecoderDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
}
.diskCache { //cache 처리를 위한 코드로 생략 가능
DiskCache.Builder()
.directory(androidApplication().cacheDir.resolve("image_cache"))
.build()
}
.build()
}
ImageLoader 는 coil 의 가이드 상, singleton 으로 관리될 때 최적의 효율을 보장하므로 이를 권장하고 있다.
Coil 을 이용한 Gif 불러오기 (feat. placeholder)
gif 를 placeholder 로 사용하고자 coil 을 이용해 gif 파일을 불러보려한다.
우선, 대상이 되는 gif 파일을 res 하위의 Android Resource Directory 중, raw 파일 하위에 추가한다. (없다면 추가해야한다.)
그리고, 아래와 같이 imageRequest 의 data 에 raw 리소스를 단순히 불러오기만 하면 간단히 구현 가능하다.
viewModelScope.launch {
val imgRequest = ImageRequest.Builder(getApplication<Application>().applicationContext)
.data(R.raw.loading)
.listener { _, result -> //결과에 다른 처리
loadingDrawable = result.drawable
}
.build()
imageLoader.execute(imgRequest)
}
....
val imgRequest = ImageRequest.Builder(getApplication<Application>().applicationContext)
.data(url)
.diskCacheKey(randomKey.toString())
.target(imageView)
.placeholder(loadingDrawable) //불러온 gif 를 placeholder 로 지정
.listener { _, result ->
imageView.setImageDrawable(result.drawable)
}
.build()
imageLoader.enqueue(imgRequest)
그리고 불러온 gif 를 Placeholder 로 지정한다.
에러 핸들링
Software Rendering dosn’t support hardware bitmaps
이제 다 되었다 라고 생각할 때 즈음, 런타임 에러가 발생하였다.
내용은 아래와 같았는데, Software rendering 이 hardware rendering 을 지원하지 않는다는 것으로, 에러는 imageview 에 setImageBitmap 하는 부분에서 발생하였다.
FATAL EXCEPTION: main
Process: com.peopleofandroido.readpictures, PID: 16644
java.lang.IllegalArgumentException: Software rendering doesn't support hardware bitmaps
at android.graphics.BaseCanvas.onHwBitmapInSwMode(BaseCanvas.java:742)
at android.graphics.BaseCanvas.throwIfHwBitmapInSwMode(BaseCanvas.java:749)
at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:94)
at android.graphics.BaseCanvas.drawBitmap(BaseCanvas.java:134)
at android.graphics.Canvas.drawBitmap(Canvas.java:1557)
at com.peopleofandroido.readpictures.presentation.viewmodel.PictureEditorViewModel.processFinalBitmap(PictureEditorViewModel.kt:385)
at com.peopleofandroido.readpictures.presentation.viewmodel.PictureEditorViewModel$setImageViewBitmap$1$1.onBitmapReady(PictureEditorViewModel.kt:357)
at ja.burhanrashid52.photoeditor.PhotoSaverTask.handleBitmapCallback(PhotoSaverTask.java:145)
at ja.burhanrashid52.photoeditor.PhotoSaverTask.onPostExecute(PhotoSaverTask.java:112)
at ja.burhanrashid52.photoeditor.PhotoSaverTask.onPostExecute(PhotoSaverTask.java:23)
at android.os.AsyncTask.finish(AsyncTask.java:771)
at android.os.AsyncTask.access$900(AsyncTask.java:199)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8855)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
발생한 원인은 Coil 에서 Bitmap 을 가져오는 과정에서 hardware rendering 이 된 것으로 보였다.
따라서, ImageRequestBuilder 의 옵션에 allowHardware 를 false 로 세팅하였으며, 이후 발생하지 않았다.
val imageLoader =ImageLoader(getApplication<Application>().applicationContext)
val imageRequest =
ImageRequest.Builder(getApplication<Application>().applicationContext)
.data(dataSignatureImageUriString)
.allowHardware(false) //false 로 세팅
.build()
val bitmap = imageLoader.execute(imageRequest).drawable?.toBitmap()
참고 링크
https://coil-kt.github.io/coil/recipes/#shared-element-transitions
https://coil-kt.github.io/coil/image_requests/
https://coil-kt.github.io/coil/gifs/
'안드로이드 > KOTLIN' 카테고리의 다른 글
[Kotlin] KtLint 로 클린한 코드 작성하기 (0) | 2023.01.30 |
---|---|
[Kotlin] 함수/람다 함수 내의 반환 return (0) | 2023.01.21 |
[Kotlin] Unit과 Nothing (0) | 2022.12.10 |
[Kotlin IN ACTION] 코틀린 타입 시스템 (0) | 2021.04.11 |
[Kotlin IN ACTION] 클래스, 객체, 인터페이스 (0) | 2021.04.04 |