nueijeel

[Android] OutOfMemoryError 본문

Android/에러 및 문제 해결

[Android] OutOfMemoryError

nueijeel 2023. 8. 22. 22:37

 

glide 라이브러리를 사용해 이미지를 출력하는 작업 중 아래와 같은 오류가 발생했다.

 

 

java.lang.OutOfMemoryError: Failed to allocate a 83070912 byte allocation with 6291456 free bytes and 12MB until OOM, max allowed footprint 396321520, growth limit 402653184

 

 

찾아보니 이미지 뷰가 담을 수 있는 이미지 용량을 넘어서 할당 오류가 발생한 것이다.

 

 

해결 시도

 

1. glide의 override 속성 지정

 

Glide.with(mainActivity).load(productImageList[position])
                .into(holder.carouselImageViewRowProductImage)

위의 원래 코드에서

Glide.with(mainActivity).load(productImageList[position])
                .override(200, 200)
                .into(holder.carouselImageViewRowProductImage)

override 속성 지정을 통해 이미지 크기를 축소해서 표시한다.

실행해보니 여전히 같은 오류가 발생했다.

 

 

2. AndroidManifest.xml에 largeHeap 속성 추가

안드로이드 프로젝트 용량이 커서 largeHeap을 사용하게 해주는 코드이다.

이것도 마찬가지로 오류가 났다.

 

 

3, Glide에 load할 이미지 형식 Bitmap으로 변경

albumLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            //이미지 가져오기 성공
            if(it.resultCode == RESULT_OK){

                //사진 여러장 선택한 경우
                if(it.data?.clipData != null){
                    val count = it.data?.clipData?.itemCount
                    
                    for(idx in 0 until count!!){
                        val imageUri = it.data?.clipData?.getItemAt(idx)?.uri
                        productImageList.add(imageUri!!)
                    }
                }
                //한장 선택한 경우
                else{
                    it.data?.data?.let { uri ->
                        val imageUri = it.data?.data
                        if(imageUri != null){
                            productImageList.add(imageUri)
                        }
                    }
                }

                //recycler view 갱신
                fragmentRegisterProductBinding.recyclerViewRegisterProductImage.adapter?.notifyDataSetChanged()
            }
        }

 

원래는 이 코드를 통해 이미지 Uri를 담은 리스트를 생성하고, 해당 리스트의 항목을 load 했었는데 bitmap 방식이 메모리가 덜 차지된다고 해서

 

uri 그대로 집어넣지 않고 bitmap으로 decode해서 load 해줬다.

//사진 여러장 선택한 경우
                if(it.data?.clipData != null){
                    val count = it.data?.clipData?.itemCount

                    //SDK 버전 P 이상
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
                        for(idx in 0 until count!!){
                            val imageUri = it.data?.clipData?.getItemAt(idx)?.uri
                            val bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(mainActivity.contentResolver, imageUri!!))
                            productImageList.add(bitmap)
                        }
                    }
                    //P 미만
                    else{
                        for(idx in 0 until count!!){
                            val imageUri = it.data?.clipData?.getItemAt(idx)?.uri
                            val bitmap = MediaStore.Images.Media.getBitmap(mainActivity.contentResolver, imageUri)
                            productImageList.add(bitmap)
                        }
                    }
                }

그런데도 안됨 ㅜㅜ

 

4. bitmapfactory.options().insamplesize 지정

 

albumLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            val option = BitmapFactory.Options()
            option.inSampleSize = 4

            //이미지 가져오기 성공
            if(it.resultCode == RESULT_OK){

                //사진 여러장 선택한 경우
                if(it.data?.clipData != null){
                    val count = it.data?.clipData?.itemCount

                    for(idx in 0 until count!!){
                        val imageUri = it.data?.clipData?.getItemAt(idx)?.uri

                        val inputStream = mainActivity.contentResolver.openInputStream(imageUri!!)
                        val bitmap = BitmapFactory.decodeStream(inputStream, null, option)

                        inputStream?.close()

                        productImageList.add(bitmap!!)
                    }

                }

BitmapFactory의 Options에 inSampleSize를 지정해 비트맵을 decode 하면 크기를 축소한 비트맵을 구할 수 있다고 해서 적용해보니까 오류가 해결됐다!!

 

 

이미지 출력은 코드만 작성하면 뷰에 알아서 뜨니까

이미지 용량까지는 생각해본 적이 없는데,, 오늘 부로 그 부분도 신경써야겠다는 걸 알게됐다!

 

 

 

 

 

참고 자료

https://kkangsnote.tistory.com/156

 

[Doit 깡샘의 안드로이드 앱 프로그래밍 with 코틀린] 정리 16 - 갤러리 앱 연동하기

본 글은 [Doit 깡샘의 안드로이드 앱 프로그래밍 with 코틀린 - 이지스퍼블리싱 (2022)] 의 내용을 발췌한 것입니다. 좀더 자세한 내용은 책 혹은 인강을 통해 확인해 주세요. HTML 삽입 미리보기할 수

kkangsnote.tistory.com

https://it77.tistory.com/99 

 

(Android) 이미지 용량 줄이기 (Bitmap 관리)

Android에서 사용하는 이미지는 Bitmap이라는 클래스에서 다~ 알아서 해줍니다. 그리고 이런 Bitmap Object를 쉽게 만들 수 있도록 도와주는 BitmapFactory 클래스 라는 것도 있습니다. BitmapFactory는 여러가

it77.tistory.com

 

728x90