[안드로이드] 갤러리 이미지 가져오기

용씨·2021년 7월 17일
1

[공경진] fillin-map

목록 보기
1/9

갤러리 이미지 가져오기

1. StartActivityForResult() 이용

1. onCreate() 함수

Intent 객체 생성, 갤러리 액티비티 실행 정보 setting

1. 코드
private val OPEN_GALLERY = 1
private var imageView: ImageView? = null
 
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        profileModifyBinding = ActivityProfileModifyBinding.inflate(layoutInflater)
        setContentView(profileModifyBinding.root)

        imageView = profileModifyBinding.profilemodifyProfileIV
        imageView?.setOnClickListener(object : View.OnClickListener {
            override fun onClick(v: View) {
                val intent = Intent(Intent.ACTION_GET_CONTENT)
                intent.setType("image/*")
                // 갤러리 액티비티로부터 가져온 결과 데이터를 처리하기 위해 
                // StartActivityForResult() 함수를 통해 액티비티를 실행
                startActivityForResult(intent,OPEN_GALLERY)
            }

        })
    }

2. onActivityResult() 함수

갤러리 액티비티로부터 결과 데이터를 처리
해당 함수의 인자는 3개입니다.

1. 첫 번째 인자

첫 번째 인자 RequestCode는 startActivityForResult() 함수의 두 번째 인자로 넘겨줬던 값과 동일한 값이 넘어온다.

2. 두 번째 인자

두 번째 인자는 resultCode로 사진을 정상적으로 선택하였다면 RESULT_OK 값이 넘어오며 뒤로가기 버튼으로 작업을 취소한 경우 RESULT_CANCELED 값이 넘어온다.

3. 세 번째 인자

세 번째 인자는 갤러리 액티비티로부터 넘어온 결과 데이터가 담겨있는 Intent 객체이다.

4. 코드
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if(requestCode == OPEN_GALLERY)
        {
            if(resultCode == RESULT_OK)
            {
            	var currentImageUri = data?.data
                
                try{
                   currentImageUri?.let {
                        if(Build.VERSION.SDK_INT < 28) {
                            val bitmap = MediaStore.Images.Media.getBitmap(
                                this.contentResolver,
                                currentImageUri
                            )
                            imageView?.setImageBitmap(bitmap)
                        } else {
                            val source = ImageDecoder.createSource(this.contentResolver, currentImageUri)
                            val bitmap = ImageDecoder.decodeBitmap(source)
                            imageView?.setImageBitmap(bitmap)
                        }
                    }
                }catch(Exception e)
                {
					e.printStackTrace()
                }
            }
            else if(resultCode == RESULT_CANCELED)
            {
                Toast.makeText(this, "사진 선택 취소", Toast.LENGTH_LONG).show();
            }
        }
    }

2. registerForActivityResult() 이용

1. ActivityLauncher 만들기

1. 코드

    private var imageView: ImageView? = profileModifyBinding.profilemodifyProfileIV

    private val filterActivityLauncher: ActivityResultLauncher<Intent> =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if(it.resultCode == RESULT_OK && it.data !=null) {
                var currentImageUri = it.data?.data
                try {
                    currentImageUri?.let {
                        if(Build.VERSION.SDK_INT < 28) {
                            val bitmap = MediaStore.Images.Media.getBitmap(
                                this.contentResolver,
                                currentImageUri
                            )
                            imageView?.setImageBitmap(bitmap)
                        } else {
                            val source = ImageDecoder.createSource(this.contentResolver, currentImageUri)
                            val bitmap = ImageDecoder.decodeBitmap(source)
                            imageView?.setImageBitmap(bitmap)
                        }
                    }


                }catch(e:Exception) {
                    e.printStackTrace()
                }
            } else if(it.resultCode == RESULT_CANCELED){
                Toast.makeText(this, "사진 선택 취소", Toast.LENGTH_LONG).show();
            }else{
                Log.d("ActivityResult","something wrong")
            }
        }

2. 설명

ActivityResultLauncher<I>
: 
registerForActivityResult(ActivityResultContract<I, O> contract, ActivityResultCallback<O> callback){}
  • Register a request to start an activity for result, designated by the given contract.

  • returns : the launcher that can be used to start the activity or dispose of the prepared call.

  • callback 람다에서 intent와 result code 등을 접근해서 원래의 onActivityResult에서 데이터를 가져오듯이 로직을 구성하면 된다.

3. 첫 번째 인자 ActivityResultContract

ActivityResultContract: the contract, specifying conversions to/from Intents
: 인턴트 변환 객체

4. 두 번째 인자 ActivityResultCallback

ActivityResultCallback: the callback to be called on the main thread when activity result is available

2. 액티비티 실행

imageView?.setOnClickListener(object : View.OnClickListener {
            override fun onClick(v: View) {
                val intent = Intent(Intent.ACTION_GET_CONTENT)
                intent.setType("image/*")
                filterActivityLauncher.launch(intent)
            }
        })

3. ActivityResultContract 커스텀

ActivityResultContract<I, O>
I : Launcher를 실행할 때의 input 타입
O : callback으로부터 떨어지는 인수의 타입

class CustomContract : ActivityResultContract<Intent, Long>() {
	// 인텐트 객체 만들기 
	override fun createIntent(context: Context, input: Intent): Intent {
          return input
      }
	// intent으로부터 전달 받은 데이터를 뽑아 리턴
	override fun parseResult(resultCode: Int, intent: Intent?): Long {
          return intent?.getLongExtra("awesome_key", -1) ?: -1
	}
}

4. Permission 요청 (한 개)

launcher를 실행할 때 내부적으로 이전 권한 설정 검사를 하고, 이미 되어있다면 바로 callback을 실행
그렇지 않으면 그때야 권한을 묻는 액티비티를 띄워준다.

private fun requestCameraPermission() {
    val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
        Toast.makeText(this, "무야호 $it", Toast.LENGTH_SHORT).show()
    }
    permissionLauncher.launch(android.Manifest.permission.CAMERA)
}

onCreate에서 해당 메서드를 호출해도 ok

5. Permission 요청 (여러 개)

private fun requestPermissions() {
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
        Log.d("권한요청", "$it")
    }.launch(PERMISSIONS_REQUESTED)
}

companion object {
    private const val PERMISSION_CAMERA = android.Manifest.permission.CAMERA
        private const val PERMISSION_READ_EXTERNAL_STORAGE = android.Manifest.permission.READ_EXTERNAL_STORAGE
        private const val PERMISSION_WRITE_EXTERNAL_STORAGE = android.Manifest.permission.WRITE_EXTERNAL_STORAGE

        private val PERMISSIONS_REQUESTED: Array<String> = arrayOf(
            PERMISSION_CAMERA,
            PERMISSION_READ_EXTERNAL_STORAGE,
            PERMISSION_WRITE_EXTERNAL_STORAGE,
        )
}

참고한 블로그
https://modelmaker.tistory.com/18
참고한 안드로이드 사이트 https://developer.android.com/reference/androidx/activity/result/ActivityResultCaller?hl=ko#registerForActivityResult(androidx.activity.result.contract.ActivityResultContract%3CI,%20O%3E,%20androidx.activity.result.ActivityResultCallback%3CO%3E)

profile
아침형 인간이 목표

0개의 댓글