Exception이 발생했다!!!!!! 으악!!!!!!! 고쳐보자 고쳐보자
이슈
- Fatal Exception: java.lang.RuntimeException
- Canvas: trying to draw too large(163840000bytes) bitmap.
android.view.DisplayListCanvas.throwIfCannotDraw
원인
- 이미지를 로딩하는 중에 해당 스마트폰의 최대 메모리를 넘어서서?
- ui보다 큰 이미지를 view에 올렸을 때?
해결 방안
1. Manifest <application>에 androd:largeHeap:"true" 추가
-> 안됨,,, 왜 안됐지 ㅜ 기억나면 다시 적어야지
2. BitmapFactory 이용하여 비트맵 사이즈 줄이기
-> 나는 BitmapUtil.kt 파일을 하나 만들었당
fun decodeSampledBitmapFromResource(
context: Context,
resId: Int,
reqWidth: Int,
reqHeight: Int
): Bitmap {
// First decode with inJustDecodeBounds=true to check dimensions
return BitmapFactory.Options().run { //디코딩을 하면서 비트맵에 메모리를 할당하려고 하므로 쉽게 OutOfMemory 예외가 발생할 수 있음
inJustDecodeBounds = true //속성 값을 true로 지정해 메모리 할당을 막음
BitmapFactory.decodeResource(context.resources, resId, this)
// Calculate inSampleSize
inSampleSize = calculateInSampleSize(this, dpToPx(context,reqWidth), dpToPx(context,reqHeight))
// Decode bitmap with inSampleSize set
inJustDecodeBounds = false
BitmapFactory.decodeResource(context.resources, resId, this)
}
}
fun dpToPx(context: Context, dp: Int): Int { //dp를 px로 바꿔주는 코드
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), context.resources.displayMetrics)
.toInt()
}
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
// Raw height and width of image
val (height: Int, width: Int) = options.run { outHeight to outWidth }
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val halfHeight: Int = height / 2
val halfWidth: Int = width / 2
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
inSampleSize *= 2
}
}
Logger.v("TAG","inSampleSize = $inSampleSize")
return inSampleSize
}
// 원본 이미지의 해상도가 2048x1536이고, inSampleSize가 4로 디코딩된 이미지는 약 512x384의 비트맵을 생성.
이 비트맵을 메모리에 로드하면 전체 이미지에 12MB 대신 0.75MB가 사용된다.
해상도는 각각 sampleSize만큼 나눠주고, memory는 2의 4제곱으로 나눠주는 듯 !
마지막으로 불러주는 곳
binding.ImageView.setImageBitmap(decodeSampledBitmapFromResource(requireContext(),R.drawable.image,100,100))
* 문제점 *
-> 갤럭시 s7 edge의 경우, 메모리에 비해 해상도가 너무 높아!! inSampleSize값이 1로 나와서 이미지 해상도가 줄여지지 않음 ㅜㅡㅜ
-> 하드코딩으로 줄여줘야함 ,,, 별로야
3. 그냥.. 이미지 해상도 줄여...
나는 기존에 1600*1600 썼는데 800*800으로 줄이니까 아주~ 자알~ 동작한다 ㅎ ㅎㅎ ㅎ;
비트맵 Exception을 잡으면서 메모리에 대해 공부 할 수 있었다.
나중엔 메모리에 대해 정리해야지 ,,,
아래는 메모리 관련 메소드!!
val am = requireActivity().getSystemService(ACTIVITY_SERVICE) as ActivityManager?
val largeMemoryClass = am!!.largeMemoryClass //이거는 largeHeap = true로 지정했을 때 최대 메모리
val memoryClass = am!!.memoryClass
Log.v(TAG, "largeMemoryClass:$largeMemoryClass")
Log.v(TAG, "memoryClass:$memoryClass")
참고 사이트 : https://developer.android.com/topic/performance/graphics/load-bitmap#java
'android' 카테고리의 다른 글
[Android] custom toast 만들기, android 11 setView is deprecated (0) | 2021.05.26 |
---|