[최신] 안드로이드 Kotlin 갤러리에서 이미지 가져오기

2022. 6. 15. 22:37개발을 파헤치다/Android

반응형

 

이미지 처리는 앱 개발 시 필수적으로 다루게 되는 부분입니다. 특히 갤러리에서 이미지 가져오기는 정말 흔하게 쓰이게 되는데요.

하지만 최근 startActivityForResult가 Deprecated 되어 약간 구현 방식이 바뀌게 되었죠. 이에 대한 내용은 많이 없더군요.

오늘은 registerForActivityResult를 활용해 갤러리에서 가져온 이미지를 ImageView에 보여주는 부분을 상세하게 알려드리겠습니다.

 

 

갤러리 이미지 처리 로직 구현

 

가장 먼저 Activity에 아래 변수들을 선언해주어야 합니다.

companion object{
        const val REVIEW_MIN_LENGTH = 10
        // 갤러리 권한 요청
        const val REQ_GALLERY = 1

        // API 호출시 Parameter key값
        const val PARAM_KEY_IMAGE = "image"
        const val PARAM_KEY_PRODUCT_ID = "product_id"
        const val PARAM_KEY_REVIEW = "review_content"
        const val PARAM_KEY_RATING = "rating"
    }
    
     // 이미지를 결과값으로 받는 변수
    private val imageResult = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ){
            result ->
        if(result.resultCode == RESULT_OK){
            // 이미지를 받으면 ImageView에 적용한다
            val imageUri = result.data?.data
            imageUri?.let{

                // 서버 업로드를 위해 파일 형태로 변환한다
                imageFile = File(getRealPathFromURI(it))

                // 이미지를 불러온다
                Glide.with(this)
                    .load(imageUri)
                    .fitCenter()
                    .apply(RequestOptions().override(500,500))
                    .into(binding.writeReviewLayout.addImageBtn)
            }
        }
    }

startActivityForResult가 Deprecated 되어 registerForActivityResult를 대신 사용해주어야 하는데요. 이 메서드는 초기화 위치가 중요합니다. onCreate나 onStart에서 초기화되지 않으면 Illegal State Exception을 발생시키기 때문입니다. 따라서 전역 변수로 설정해주면 됩니다.

아래에서 설명할 갤러리를 Intent를 통해 호출하는 메서드를 실행하면 그 결과로 위의 로직이 호출됩니다. 이때 이미지의 Uri 값이 리턴되는데요. 제대로 값이 온다면 해당 Uri 값을 Glide를 통해 ImageView에 적용할 수 있습니다. 만약 API 호출을 한다면 파라미터로 이미지를 포함시킬 수도 있습니다. 다만, 이때에는 이미지의 경로를 찾아 File 형태로 추가해줘야 합니다. 이를 위해 getRealPathFromUri 메서드를 아래와 같이 구현합니다.

 

 // 이미지 실제 경로 반환
fun getRealPathFromURI(uri: Uri): String {

    val buildName = Build.MANUFACTURER
    if (buildName.equals("Xiaomi")) {
        return uri.path!!
    }
    var columnIndex = 0
    val proj = arrayOf(MediaStore.Images.Media.DATA)
    val cursor = contentResolver.query(uri, proj, null, null, null)
    if (cursor!!.moveToFirst()) {
        columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
    }
    val result = cursor.getString(columnIndex)
    cursor.close()
    return result
}

 

갤러리 호출하기 구현 (feat. 권한 처리)

이제 갤러리를 호출하는 메서드를 구현해봅시다.

설명하기 이전에 먼저 권한 얘기를 해야 하는데요. 이미지를 불러오기 위해서는 외부 저장소 접근 권한이 필요합니다. 그렇기 때문에 Android.Manifest 파일에 아래와 같이 권한을 추가해줍니다.

 

<!--갤러리 권한-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

권한을 추가했어도 사용자에게 권한을 요청하고 사용자가 허용하는지 거부하는지에 따라 로직을 직접 구현해줘야 합니다.

 // 갤러리를 부르는 메서드
private fun selectGallery(){
    val writePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    val readPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)

    //권한 확인
    if(writePermission == PackageManager.PERMISSION_DENIED ||
            readPermission == PackageManager.PERMISSION_DENIED){
        // 권한 요청
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.READ_EXTERNAL_STORAGE), REQ_GALLERY)

    }else{
        // 권한이 있는 경우 갤러리 실행
        val intent = Intent(Intent.ACTION_PICK)
        // intent의 data와 type을 동시에 설정하는 메서드
        intent.setDataAndType(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            "image/*"
        )

        imageResult.launch(intent)
    }
}

권한이 허용된 상태가 아니라면 권한을 요청합니다. 사용자에게 필요한 권한이 알림 창으로 뜨고 허용할 것인지 말 것인지 선택하는 화면이 나오는데요. 사용자의 선택에 따른 결과는 onRequestPermissionResult 메서드에서 처리해줘야 합니다. 이에 대한 자세한 처리는 아래 글을 참고하시면 됩니다.

2021.11.04 - [개발을 파헤치다/Android] - 안드로이드 권한 요청 이거 하나로 끝낸다


권한이 있으면 갤러리를 호출합니다. 갤러리가 나타나고 사용자가 이미지를 선택하면 위의 imageResult에 등록된 로직이 호출됩니다. result 코드에 따라 이미지 Uri 값을 받아와 Glide를 통해 ImageView에 보여주는 로직이 실행됩니다. 만약 이미지를 선택하지 않으면 로직이 실행되지 않습니다.

 

 

반응형