관리 메뉴

나만을 위한 블로그

[Android] CameraX 코드랩 뜯어보기 - 2 - 본문

Android

[Android] CameraX 코드랩 뜯어보기 - 2 -

참깨빵위에참깨빵 2023. 3. 26. 00:56
728x90
반응형

https://onlyfor-me-blog.tistory.com/490

 

[Android] CameraX 코드랩 뜯어보기 - 1 -

카메라는 내게 많이 생소한 영역이기도 하고 예전에 CameraX인지 뭔지가 새로 나왔다고 들었어서 최근에 코드랩을 따라 쳐보고 공부하긴 했었는데, 블로그에 남겨두면 나중에 찾아보기 더 좋을

onlyfor-me-blog.tistory.com

 

1편에서 뼈대 코드들을 만들었으니 이제 카메라를 쓰기 위해 유저에게 권한을 요청하는 처리를 구현한다. 카메라 기능을 사용하기 위해선 권한이 필요하고 이후 소리를 녹음하는 기능도 구현하기 때문에 여러 권한들을 매니페스트에 지정한다.

 

<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
   android:maxSdkVersion="28" />

 

안드로이드 파이 버전 이하에선 외부 저장소 쓰기 권한이 필요하다. 그래서 외부 저장소 권한을 추가했고 맨 위의 android.hardware.camera.any를 추가하면 이 앱을 실행하는 단말에 카메라가 있는지 여부를 확인할 수 있다. ".any"를 지정하면 전면 또는 후면 카메라 모두를 확인한다. ".any"를 쓰지 않으면 후면 카메라가 없을 경우 앱이 작동하지 않을 수 있다. 이와 관련된 디벨로퍼 링크는 아래에 첨부한다. android.hardware.camera.any의 내용은 밑으로 조금만 스크롤하면 나온다.

 

https://developer.android.com/guide/topics/manifest/uses-feature-element#features-reference

 

Android 개발자  |  Android Developers

"애플리케이션이

developer.android.com

앱은 장치의 카메라 중 하나 또는 장치에 연결된 외부 카메라를 사용한다. 앱에서 카메라가 각각 후면 또는 전면을 향하도록 요구하지 않는 경우 android.hardware.camera 또는 android.hardware.camera.front 대신 이것을 사용하라. 후면 카메라는 android.hardware.camera가 android.required="false"로 선언되지 않는 한 필수 기능이다.
전면 카메라만 있는 Chromebook 같은 장치는 이 기능을 지원하지 않는다. 앱에서 모든 카메라를 쓸 수 있다면 android.hardware.camera.any를 사용하라

 

그리고 MainActivity에 이 함수를 재정의한다.

 

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_CODE_PERMISSIONS) {
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            Toast.makeText(this, "권한이 승낙되지 않아서 앱이 종료됨", Toast.LENGTH_SHORT).show()
            finish()
        }
    }
}

 

이 함수는 현재 deprecated된 함수다. 이것을 쓰는 것보단 TedPermission을 쓰거나 디벨로퍼에서 제시하는 방식을 사용한다. 권한 부분만 바꾸는 것은 어렵지 않으니 생략한다.

 

https://developer.android.com/training/permissions/requesting?hl=ko#manage-request-code-yourself 

 

런타임 권한 요청  |  Android Developers

런타임 권한 요청 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 모든 Android 앱은 액세스가 제한된 샌드박스에서 실행됩니다. 앱이 자체 샌드박스 밖에 있

developer.android.com

 

다시 코드를 보면 권한이 허용된 경우 startCamera()를 통해 카메라 기능을 시작한다. 앱을 실행해서 권한 요청 팝업이 표시되는지 확인한다. startCamera()는 시그니처만 만들어 둔 상태라 컴파일 에러는 발생하지 않겠지만 아무 기능도 하지 않는다.

 

뷰파인더는 사용자가 찍을 사진을 미리 볼 수 있게 하기 위해서 사용한다. 여기선 CameraX Preview 클래스를 통해 뷰파인더를 구현한다. 이제 startCamera() 안에 아래 내용을 복붙한다.

 

private fun startCamera() {
   val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

   cameraProviderFuture.addListener({
       // Used to bind the lifecycle of cameras to the lifecycle owner
       val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

       // Preview
       val preview = Preview.Builder()
          .build()
          .also {
              it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
          }

       // Select back camera as a default
       val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

       try {
           // Unbind use cases before rebinding
           cameraProvider.unbindAll()

           // Bind use cases to camera
           cameraProvider.bindToLifecycle(
               this, cameraSelector, preview
           )
       } catch(exc: Exception) {
           Log.e(TAG, "Use case binding failed", exc)
       }

   }, ContextCompat.getMainExecutor(this))
}

 

ProcessCameraProvider의 인스턴스를 만드는 것은 카메라의 생명주기를 lifecycleOwner에 바인딩하기 위해서다. CameraX는 앱의 생명주기를 인식할 수 있기 때문에 카메라를 열고 닫는 작업이 필요없다.

그리고 곧바로 ProcessCameraProvider의 인스턴스에 리스너를 추가하고 Runnable을 매개변수로 넘긴다. ContextCompat.getMainExecutor()는 메인 쓰레드에서 실행되는 Executor를 반환하는 역할을 한다. 그리고 Runnable 안에서 ProcessCameraProvider를 만드는데 이것은 앱 프로세스에서 카메라의 생명주기를 lifecycleOwner에 바인딩하기 위해 사용되는 클래스다. 카메라 기능에 대한 접근을 캡슐화, 관리하는 클래스로 카메라 기능 개발을 단순화하기 위해 설계된 Jetpack 구성요소다.
카메라 관련  그 다음 Preview 객체를 초기화한 다음 PreviewView에서 surface provider를 가져와 미리보기에 설정한다. 후면 카메라를 사용하게 설정하고 try 블록에서 cameraProvider에 바인딩된 것들을 해제하고 위에서 설정한 cameraSelector, preview 객체를 cameraProvider에 바인딩한다.

이제 에뮬레이터나 실제 핸드폰에서 앱을 빌드하면 아래와 같이 표시된다.

 

 

반응형
Comments