달력형 위젯을 구현 중, Background ImageView에 디자이너분이 제작해 주신
테마 이미지를 Bitmap으로 삽입하던 중 다음과 같은 오류가 발생했다.
java.lang.IllegalArgumentException:
RemoteViews for widget update exceeds maximum bitmap memory usage
(used: 7474416, max: 6432000)
무슨 오류인가.. 확인해 보니 Bitmap 메모리 사용량이 한도를 초과한 것이다.
이미지 크기와 해상도가 상이하기 때문에 충분히 발생할 수 있다고 생각했다.
위젯에 최적화된 이미지를 다시 제작하기 전까지는 임시로 크기를 줄여서라도 사용하기로 결정했다.
fun getBitmapSize(file: File): Size {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
val imageWidth = options.outWidth
val imageHeight = options.outHeight
return Size(imageWidth, imageHeight)
}
일단 표시할 이미지 파일을 인자로 받아 Bitmap Size를 측정했다.
inJustDecodeBounds true일 경우, Bitmap의 크기 정보만을 가져올 수 있다.
일단 limit 사이즈를 720f으로 낮게 잡았다.
처음에는 1080f로 잡았었는데, 그래도 이슈가 재현되었다...
if (file.exists()) {
val checkedLargeSize = getBitmapSize(file).run { max(this.width, this.height) }.toFloat()
if (checkedLargeSize < limitedSize) {
BitmapFactory.decodeFile(file.absolutePath)
} else {
scaledImage(file, ceil(checkedLargeSize / limitedSize).toInt() )
}
} else {
null
.
.
.
remoteViews.setImageViewBitmap(imageViewId, bitmap)
가로, 세로 값을 각각 측정하여 둘 중 더 큰 값과 limit 값을 비교하여 가로, 세로 모두 limit 미만일 경우에는
그대로 해당 Bitmap을 decode 하여 사용한다.
fun scaledImage(file: File, scaleFactor: Int): Bitmap {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = false
options.inSampleSize = scaleFactor
return BitmapFactory.decodeFile(file.absolutePath, options)
}
하지만 limit 이상일 경우에는 inSampleSize를 활용하여 크기를 지정해 준다.
inSampleSize를 2로 설정하면 가로, 세로 크기를 절반으로 줄여 해상도를 낮출 수 있다.
scaledImage(file, ceil(checkedLargeSize / limitedSize).toInt() )
최대한 큰 값을 scaleFactor로 사용하는 것이 좋을 것 같아 실제 Size / limit Size의 올림 값을 사용했다.
이후 일단 더 이상 Crash Report는 오지 않고 있다.
하지만 Bitmap의 크기가 출시되는 테마마다 상이할 수 있기 때문에 계속 지켜봐야 할 부분이다...
달력형 위젯을 구현 중, Background ImageView에 디자이너분이 제작해 주신
테마 이미지를 Bitmap으로 삽입하던 중 다음과 같은 오류가 발생했다.
java.lang.IllegalArgumentException:
RemoteViews for widget update exceeds maximum bitmap memory usage
(used: 7474416, max: 6432000)
무슨 오류인가.. 확인해 보니 Bitmap 메모리 사용량이 한도를 초과한 것이다.
이미지 크기와 해상도가 상이하기 때문에 충분히 발생할 수 있다고 생각했다.
위젯에 최적화된 이미지를 다시 제작하기 전까지는 임시로 크기를 줄여서라도 사용하기로 결정했다.
fun getBitmapSize(file: File): Size {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
val imageWidth = options.outWidth
val imageHeight = options.outHeight
return Size(imageWidth, imageHeight)
}
일단 표시할 이미지 파일을 인자로 받아 Bitmap Size를 측정했다.
inJustDecodeBounds true일 경우, Bitmap의 크기 정보만을 가져올 수 있다.
일단 limit 사이즈를 720f으로 낮게 잡았다.
처음에는 1080f로 잡았었는데, 그래도 이슈가 재현되었다...
if (file.exists()) {
val checkedLargeSize = getBitmapSize(file).run { max(this.width, this.height) }.toFloat()
if (checkedLargeSize < limitedSize) {
BitmapFactory.decodeFile(file.absolutePath)
} else {
scaledImage(file, ceil(checkedLargeSize / limitedSize).toInt() )
}
} else {
null
.
.
.
remoteViews.setImageViewBitmap(imageViewId, bitmap)
가로, 세로 값을 각각 측정하여 둘 중 더 큰 값과 limit 값을 비교하여 가로, 세로 모두 limit 미만일 경우에는
그대로 해당 Bitmap을 decode 하여 사용한다.
fun scaledImage(file: File, scaleFactor: Int): Bitmap {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = false
options.inSampleSize = scaleFactor
return BitmapFactory.decodeFile(file.absolutePath, options)
}
하지만 limit 이상일 경우에는 inSampleSize를 활용하여 크기를 지정해 준다.
inSampleSize를 2로 설정하면 가로, 세로 크기를 절반으로 줄여 해상도를 낮출 수 있다.
scaledImage(file, ceil(checkedLargeSize / limitedSize).toInt() )
최대한 큰 값을 scaleFactor로 사용하는 것이 좋을 것 같아 실제 Size / limit Size의 올림 값을 사용했다.
이후 일단 더 이상 Crash Report는 오지 않고 있다.
하지만 Bitmap의 크기가 출시되는 테마마다 상이할 수 있기 때문에 계속 지켜봐야 할 부분이다...