오늘도 삽질중

Android 특정 이미지만 trying to use a recycled bitmap 에러가 발생한다면? 본문

안드로이드

Android 특정 이미지만 trying to use a recycled bitmap 에러가 발생한다면?

Choi3950 2021. 1. 21. 21:50
반응형

갤러리에서 사진 선택시 이미지뷰에 출력하는 과정에서 

특정사진만 클릭시 trying to use a recycled bitmap 에러가 발생하는 상황이 생겼다.


다른 사진은 이상없는데....도데체 왜? 이유가 뭐지?

그렇다고 호출 시점이 잘못된게 절대 아니다. 

애초에 잘못 됬다면 다른 사진도 모두 에러가 발생해야되는게 맞으니까



우선 그전에 다 아는 내용이겠지만 recycle() 은 꼭 호출하지 않아도 된다.

JVM 이 알아서 비트맵에 할당된 메모리를 해제해 준다고 한다.

그럼에도 내가 호출하는 이유는

1. JVM이 스스로 메모리를 해제하기 보다 내가 직접 제어하고 싶다.

2. 채팅에서 이미지 업로드 중간에 썸네일을 보여주는 과정이므로 메모리 관리가 중요하다고 판단했다.



물론 그냥 쉽게 가고싶다면 recycle() 함수를 호출 안하면 된다.

주석처리하고 테스트해보니 내가 원하는 대로 너무 잘된다.



자...서론은 그만하고 왜 에러가 났는지 내 상황을 얘기해보자면

사진의 해상도 즉 사이즈가 다른 일반 사진에 비해 너무나 작다.


보통 갤러리에서 사진을 선택하면 해상도가 4032 x 3024 , 1080 x 2280 이게 보편적일것이다.

근데 에러가 발생한 사진은 해상도가 320 x 480 으로 보편적인 해상도 보다 너무나 낮다.


이유는 모르겠지만 해상도가 보편적인 경우보다 현저하게 낮을 경우 recycle()을 호출하면 크래시가 발생한다.

혹시나해서 Hander 로 딜레이를 5초 이상 줘봤는데 에러가 발생하지 않았다.

5초는 너무 긴거 같아서  0.5초정도 주니 3번중에 1번꼴로 에러가 발생해서 해상도, 즉 이미지의 가로세로 사이지를 체크해서 일정 사이즈 미만은  recycle()을 호출하지 않는 로직으로 변경했다.


어차피 사이즈가 작으면....메모리도 적게 할당이 될테고 이정도는 운영체제에게 위임해도 될 정도라고 판단했기 때문이다.


Boolean 변수를 하나 추가 후 기준 사이즈보다 작을 경우 recycle() 을 호출하지 않도록 변경한 코드다.


private fun loadThumbnail(imageView: AppCompatImageView, filPath: String, strandSize: Int) {
PLog.e("loadThumbnail GO :::: $filPath")
//이미지가 너무 작을경우 recycle() 호출시 크래쉬 발생하여 사이즈 체크해서 recycle 여부 판단
var goRecycle = true
try {
val options = BitmapFactory.Options()
val originalBitmap = BitmapFactory.decodeFile(filPath, options)

val imageWidth = options.outWidth
val imageHeight = options.outHeight

if (imageWidth == 0 || imageHeight == 0) return

var reSizeWidth: Int = 0
var reSizeHeight: Int = 0

if (imageWidth > imageHeight) {
if (imageWidth > strandSize) {
reSizeWidth = imageWidth / 2
reSizeHeight = imageHeight / 2
} else {
reSizeWidth = imageWidth
reSizeHeight = imageHeight
goRecycle = false
}
} else {
if (imageHeight > strandSize) {
reSizeWidth = imageWidth / 2
reSizeHeight = imageHeight / 2
} else {
reSizeWidth = imageWidth
reSizeHeight = imageHeight
goRecycle = false
}

}

val layoutParams = imageView.layoutParams
layoutParams.width = reSizeWidth
layoutParams.height = reSizeHeight

val thumbnailBitmap = Bitmap.createScaledBitmap(originalBitmap, reSizeWidth, reSizeHeight, false)
imageView.setImageBitmap(thumbnailBitmap)

if (!originalBitmap.isRecycled) {
if (goRecycle) {
originalBitmap.recycle()
}
}
} catch (e: Exception) {
e.printStackTrace()
imageView.visibility = View.GONE
}
}



혹시나 다른 이유를 아시는 분은 검색키워드 라도 알려주시면 감사하겠습니다...!




반응형
Comments