16. [콘텐츠 프로바이더 컴포넌트]

728x90

[16. 콘텐츠 프로바이더 컴포넌트]

[16-1. 콘텐츠 프로바이더 이해]

 

[콘텐츠 프로바이더]

-콘텐츠 프로바이더 : 앱의 데이터를 다른 앱과 공유할 때 사용

-데이터 : 대상 앱의 데이터베이스/파일/앱에 할당된 메모리 등에 존재

[콘텐츠 프로바이더 생성/등록]

    <생성>

-ContentProvider 클래스 상속받은 후내부에 onCreate() / getType() / query() / insert() / update() / delete() 함수 재정의
    <등록>

-이 역시 컴포넌트이므로 매니페스트에 등록 필수
-<provider> 태그로 등록.
     name 속성에 등록할 클래스명 지정 + authorities 속성에 식별 문자열 지정 필수

 

[콘텐츠 프로바이더 사용]

-인텐트와 관련 X

-필요한 순간에 시스템에서 자동 생성해주므로 내부에 재정의한 함수만 호출해주면 됨

   ① [외부 앱에서 콘텐츠 프로바이더 사용]

-매니페스트에 해당 앱 패키지 공개 설정해주어야 함

           1) 대상앱 패키지명을 <package> 태그로 명시           OR

           2) 사용하려는 콘텐츠 프로바이더의 authorities 속성을 <provider> 태그로 선언

   ② [시스템에 등록된 콘텐츠 프로바이더 사용]

-ContentResolver 객체 이용

-contentResolver 속성으로 ContentResolver 객체 얻은 후, 데이터 조작함수 호출함

delete()
insert()
query()
update()

-이 함수들의 첫 번째 매개변수는 대상 콘텐츠 프로바이더 식별하는 URI 객체.

-URI객체의 < URL 문자열 형식 >

         1) 프로토콜명 + 호스트

content://com.example.test_provider

         2) 프로토콜명 + 호스트 + (경로) : 경로는 선택사항이지만, 대개 조건명시에 사용

content://com.example.test_provider/user/1

                -단어로 끝나면 : 단어에 해당하는 모든 데이터 의미

                -숫자로 끝나면 : 숫자로 식별되는 데이터 의미


[16-2. 안드로이드 기본 앱과 연동]

⇒  [주소록 앱 연동]

     ① 주소록 앱 사용 퍼미션 설정

<uses-permission android:name=“android.permission.READ_CONTACTS”/>

     ② 주소록 목록 화면 띄우기 코드 작성

-인텐트로 목록 화면 실행

val intent = Intent(Intent.ACTION_PICK ,  ContactsContract.CommonDataKinds.Phone.CONTENT_URI)
                  //액션문자열 지정        //URi객체 연동 시 사용할 데이터 정보 상수값 지정 
requestContactsLauncher.launch(intent) //시스템에 정의한 인텐트 전달 
                      -인텐트 액션문자열 Intent.ACTION_PICK 으로 지정
                      -데이터 정보 Uri 객체에 연동 시 사용할 상수값 지정
                      -정의한 인텐트를 ActivityResultLauncherlaunch() 함수로 시스템에 전달

            <데이터 정보 상수>

ContactsContract.Contacts.CONTENT_URI 모든 사람 데이터
ContactsContract.CommonDataKinds.Phone.CONTENT_URI 전화번호 있는 사람 데이터
ContactsContract.CommonDataKinds.Email.CONTENT_URI 이메일 정보 있는 사람 데이터

     주소록에서 한 사람 선택 시 실행되는 함수

-출력된 목록 화면에서 사용자가 사람 선택하여 되돌아오면

                                   ActiityResultCallbackonActivityResult() 함수가 자동 실행됨

-이 함수의 매개변수로 주소록 앱에서 전달한 데이터 받을 수 있는데, 전달받은 URL 마지막 단어가 선택한 사용자 고유 식별값


    <콘텐츠 프로바이더 이용> : 식별값 이용 구체적인 추가 데이터 다시 요청

-주소록 앱의 콘텐츠 프로바이더를 이용함

-프로바이더 이용하여 가져올 데이터를 지정하는데, 지정값에 따라 데이터 가져옴

ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME 이름
ContactsContract.CommonDataKinds.Phone.NUMBER 전화번호

⇒  [갤러리 앱 연동]

<이미지 작업 시 고려사항>

   ① 안드로이드에서 이미지 Drawable 이나 Bitmap 객체로 표현  (둘은 상호호환O)

Drawable 리소스 이미지 표현
Bitmap 파일, 네트워크로 내려받은 이미지 표현

   ② Bitmap 객체는 BitmapFactory 클래스로 생성

 <BitmapFactory 제공 Bitmap 생성 함수>: decode 로 시작

BitmapFactory.decodeByteArray() byte[] 배열 데이터로 비트맵 생성
BitmapFactory.decodeFile() 파일로부터 읽어들인 데이터로 생성
BitmapFactory.decodeResource() 리소스 이미지로 비트맵 생성
BitmapFactory.decodeStream() InputStream으로 읽은 데이터로 생성

   ③ BitmapFacory의 함수로 Bitmap 생성 시, OOM 오류 고려할 것

               *OOM : 용량 커서 발생 오류

-생성 함수의 매개변수에 따로 옵션 지정 X -> 원본 그대로 읽어들여서 OOM 발생

-생성 함수의 매개변수에 옵션 지정할 것 : 이미지 크기 줄이기 inSampleSize 속성

   ④ 이미지 처리 라이브러리 이용이 더 효율적인 경우 존재 O : Glide/Picasso


[갤러리 앱 연동 방법]

   Ⓐ 인텐트로 갤러리 앱의 사진 목록 출력하기

       <인텐트 세팅>
-인텐트 액션 문자열 : Intent.ACTION_PICK 지정
-데이터 상수값 : MediaStore.Images.Media.EXTTERNAL_CONTENT_URI 지정
-타입 : image/* 로 지정
        <지정한 인텐트 정보 전달>
requestGalleryLauncher.launch(intent) //전달
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = “image/*“
requestGalleryLauncher.launch(intent)​

   Ⓑ 갤러리 앱 사진 목록에서 사용자 선택 사진을 액티비티 화면에 출력하기

<inSampleSize값 옵션 지정하여 이미지 크기 줄이기>

<이미지 불러오기 >
-contentResolver.openInputStream(data!!.data!!) 구문
               //갤러리 앱의 ‘콘텐츠 프로바이더’가 제공하는 InputStream 객체 가져오는 구문
                 //이 객체에 사용자가 선택한 사진 데이터 담겨있음

⇒  [카메라 앱 연동]

   ① [사진 데이터를 가져오는 방법 ]

-카메라 앱으로 사진 촬영 후 (파일로 저장X) 데이터만 넘겨주는 방식

       <인텐트로 사진촬영 액티비티 실행>

-카메라 실행 -> 사용자 사진 촬영 후 -> 다시 내가 만든 앱으로 되돌아옴

val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) //액션 문자열 지정
requestCameraThumbnailLauncher.launch(intent) //시스템에 전달

 

       <카메라앱에서 넘어온 사진 데이터 가져오기>

requestCameraThumbnailLauncher = registerForACtivityResult( 
   ActivityResultContracts.StartsActivityForResult() )
{
    val bitmap = it?.data?.extras?.get(“data”) as Bitmap
}​

[ 사진 파일을 공유하는 방법 ]

-카메라 앱으로 사진 촬영 후 (파일로 저장O) 저장 실패/성공 여부만 넘겨주는 방식

           <파일 공유 준비 작업’>

     (1) 외장 메모리에 사진 저장할 파일 만들어 줘야 함
       
           <파일 생성 함수> 
         ▶getExternalStoragePublicDirectory() 로 파일 생성 : 모든 앱에서 이용 O 파일 생성
                                                                   -> 이 함수 사용 시. 따로 퍼미션 설정 필요

         ▶getExternalFilesDir() 로 파일 생성이 앱에서만 이용O 파일 생성

      *API 레벨 24부터. “file://프로토콜구성 URI는 외부 노출 X : 엄격모드 적용

      *따라서, 앱끼리 파일 공유하려면 content://프로토콜 구성 URI 이용 +  URI에 임시 접근 권한 부여 필요해짐

     (2) FileProvider 클래스 사용

파일 프로바이더용 XML 파일
-이 파일의 path 속성에 지정한 경로의 파일 권한 설정
-이 경로가 getExternalFilesDir() 함수로 파일 만들었을 때 파일 저장되는 위치

매티페스트 파일에 파일 프로바이더용 XML’ 파일을 등록
    <provider>로 등록 시.
            하위에 <meta-data> resource 속성에 프로바이더용 XML 파일 지정

 

           <코드에서 카메라 앱 연동>

   ① 파일 만들기

val timeStamp: String = SimpleDateFormat(“yyyyMMdd_HHmmss”).format(Date())
val storageDir : File? = getExternalFilesDir(Environment,DIRECTORY_PICTURES)
val file = File.createTempFile(  //파일명 중복되지 않도록 날짜와 시간을 이용 
    “JPEG_${timeStamp}_”, 
    “.jpg”,
    storageDir
)
filePath = file.absolutePath //나중에 파일 내용 읽을 때 사용 목적 파일 경로 저장

  ② 카메라 앱 실행 인텐트 준비

-앞에서 설정 정보 바탕으로 FileProvider 이용 Uri 객체 만들고

            이를 카메라 앱 실행 인텐트의 엑스트라 데이터로 설정

val phothURI:Uri = FileProvider.getUriForFile(
    this,
   “com.example.test16.fileprovider”, file
)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);  
requestCameraFileLauncher.launch(intent)

   ③ 비트맵 이미지 생성

-촬영 후 다시 앱으로 돌아왔을 때 실행될 코드

requestCameraFileLauncher = registerForActiviryResult(
   ActivityResultContracts.StartActivityForResult())
{
   val option = BitmapFactory.Options()
   option.inSampleSize = 10 //사이즈 줄이고

   val bitmap = BitmapFactory.decodeFile(filePath, option)  //비트맵 사진 생성 
   bitmap?.let{
      binding.cameraFileResult.setImageBitmap(bitmap)
   }
}​

⇒  [지도 앱 연동]

      (1) 인텐트 세팅
           -액션문자열 Intent.ACTION_VIEW 지정
           -데이터 정보에 보여줄 지도 특정위치 (geo: 위도, 경도) 지정한 URL 값 지정

      (2) 세팅한 인텐트를 시스템에 전달
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(“geo: 37.5662952, 126.9779451”))
                      // (액션 문자열 지정 ,    인텐트 데이터 정보에 (위도, 경도) 지정 )
startActivity(intent) //시스템에 전달​

⇒  [전화 앱 연동]

      (1) 인텐트 세팅
         -액션문자열 Intent.ACTION_CALL 지정
         -데이터 정보에 전화 걸 번호 데이터 지정 | “tel: 전화번호

      (2) 세팅한 인텐트를 시스템에 전달
val intent = INtent(Intent.ACTION_CALL, Uri.parse(“tel:02-120”))
startActivity(intent) //시스템에 전달

[16-3. 카메라, 갤러리 앱과 연동 앱 만들기] : 실습

 

[참고] : Do It 안드로이드 앱 프로그래밍 with 코틀린 

728x90