[Android] ContentProvider

leeehaยท2022๋…„ 11์›” 6์ผ
0
post-thumbnail

ContentProvider

  • ์•ฑ๊ณผ ์•ฑ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์—ฐ๋™์„ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ

  • ContentProvider๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ์ž‘์„ฑ

  • AndroidManifest.xml ํŒŒ์ผ์— ๋“ฑ๋ก (์ปดํฌ๋„ŒํŠธ๋Š” ๋“ฑ๋ก ํ•„์ˆ˜)
  • ํ•„์ˆ˜ ์†์„ฑ: name, authorities

  • ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”๋Š” ์ธํ…ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์œผ๋ฉฐ, ํ•„์š”ํ•œ ์ˆœ๊ฐ„์— ์‹œ์Šคํ…œ์—์„œ ์ž๋™์„ ์ƒ์„ฑํ•œ๋‹ค.
  • ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•ฑ์€ query(), insert(), delete(), update() ํ•จ์ˆ˜๋งŒ ํ˜ธ์ถœ
  • ์™ธ๋ถ€ ์•ฑ์˜ ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ด์šฉํ•˜๋ ค๋ฉด, ํ•ด๋‹น ์•ฑ์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ Query Visibility ๊ด€๋ จ ์„ค์ •์„ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.
  • ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ์•ฑ์˜ ํŒจํ‚ค์ง€๋ช…์„ ํƒœ๊ทธ๋กœ, ํ˜น์€ ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”์˜ authorities ๋ฌธ์ž์—ด์„ ํƒœ๊ทธ๋กœ ์„ ์–ธ

  • ์‹œ์Šคํ…œ์˜ ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด๊ฐ€ ContentResolver ๊ฐ์ฒด
  • ContentResolver ๊ฐ์ฒด๋Š” contentResolver ํ”„๋กœํผํ‹ฐ๋กœ ํš๋“ํ•˜์—ฌ query(), insert(), delete(), update() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ

  • ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ Uri ๊ฐ์ฒด


์ฃผ์†Œ๋ก ์•ฑ

์ฃผ์†Œ๋ก ์•ฑ์„ ์—ฐ๋™ํ•˜์—ฌ ์ฃผ์†Œ๋ก ๋ชฉ๋ก ํ™”๋ฉด (์•กํ‹ฐ๋น„ํ‹ฐ)์„ ๋„์šฐ๊ณ , ์œ ์ €๊ฐ€ ์„ ํƒํ•œ ์‚ฌ๋žŒ์˜ ์ „ํ™”๋ฒˆํ˜ธ ํ˜น์€ ์ด๋ฉ”์ผ ์ •๋ณด๋ฅผ ์–ป์–ด๋ณด์ž! (์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”)

ํผ๋ฏธ์…˜ ๋ถ€์—ฌ (๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ)

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

์ฃผ์†Œ๋ก์˜ ๋ชฉ๋ก ํ™”๋ฉด ๋„์šฐ๊ธฐ

  • ContentsContract.Contacts.CONTENT_URI : ๋ชจ๋“  ์‚ฌ๋žŒ ์ถœ๋ ฅ
  • ContentsContract.CommonDataKinds.Phone.CONTENT_URI : ์ „ํ™”๋ฒˆํ˜ธ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ๋งŒ ์ถœ๋ ฅ
  • ContentsContract.CommonDataKinds.Email.CONTENT_URI : ์ด๋ฉ”์ผ์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋งŒ ์ถœ๋ ฅ
val intent = Intent(Intent.ACTION_PICK, ContentsContract.CommonDataKinds.Phone.CONTENT_URI) 
requestActivity(intent) // ์•”์‹œ์  ์ธํ…ํŠธ ์ „๋‹ฌ 
  • ์ฃผ์†Œ๋ก์œผ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ ๋ฐ›์€ ๊ฒฐ๊ณผ๋Š” URL ๋ฌธ์ž์—ด ํ˜•ํƒœ์ด๋ฉฐ, URL์˜ ๋งจ ๋งˆ์ง€๋ง‰ ๋‹จ์–ด๊ฐ€ ์œ ์ €๊ฐ€ ์„ ํƒํ•œ ์‚ฌ๋žŒ์˜ ์‹๋ณ„์ž ๊ฐ’์ด ๋œ๋‹ค.
  • ์ด ์‹๋ณ„์ž ๊ฐ’์„ ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”์—๊ฒŒ ์ œ๊ณตํ•˜๋ฉด, ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹ค์Šต ์˜ˆ์ œ

<uses-permission android:name="android.permission.READ_CONTACTS"/>
package com.tutorial.c63

import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.provider.ContactsContract
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        val resultView = findViewById<TextView>(R.id.resultView)

        // ๋‹ค๋ฅธ ์•กํ‹ฐ๋น„ํ‹ฐ๋กœ๋ถ€ํ„ฐ ๊ฒฐ๊ณผ ๊ฐ’์„ ๋ฐ›๋Š” ๊ฒฝ์šฐ -> StartActivityForResult
        val requestActivity = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) {
        	// ์ปจํ…์ธ  ํ”„๋กœํŒŒ์ด๋”์—๊ฒŒ ๋ฐ์ดํ„ฐ ์š”์ฒญ 
            val cursor = contentResolver.query(
                it.data!!.data!!, // ์œ ์ €๊ฐ€ ์„ ํƒํ•œ ํ•ญ๋ชฉ์˜ ์‹๋ณ„์ž ๊ฐ’ (uri)
                arrayOf(
                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, // ์ด๋ฆ„
                    ContactsContract.CommonDataKinds.Phone.NUMBER // ์ „ํ™”๋ฒˆํ˜ธ
                ),
                null,
                null,
                null
            )

            var name = "none"
            var phone = "none"
            if (cursor!!.moveToFirst()) {
                name = cursor.getString(0)
                phone = cursor.getString(1)
            }

            // ์ด๋ฆ„๊ณผ ์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ํ…์ŠคํŠธ๋ทฐ์— ๋ณด์—ฌ์ฃผ๊ธฐ
            resultView.text = "result: name - ${name}, phone - ${phone}"
        }

        // ์ฃผ์†Œ๋ก์— ๋Œ€ํ•œ ํผ๋ฏธ์…˜ ์š”์ฒญ
        val permissionLauncher = registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted ->
            if (isGranted) { // ํผ๋ฏธ์…˜์ด ํ—ˆ์šฉ๋˜๋ฉด
                // ์ฃผ์†Œ๋ก ๋ชฉ๋ก ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ€๊ธฐ
                val intent = Intent(
                    Intent.ACTION_PICK,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI // ์ „ํ™”๋ฒˆํ˜ธ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ๋งŒ ์ถœ๋ ฅ 
                )
                requestActivity.launch(intent)
            } else {
                Toast.makeText(this, "permission denied", Toast.LENGTH_SHORT).show()
            }
        }

        button.setOnClickListener {
            // ์ฃผ์†Œ๋ก ํผ๋ฏธ์…˜ ํ—ˆ์šฉ ์—ฌ๋ถ€ ํ™•์ธ
            val status = ContextCompat.checkSelfPermission(this,
                "android.permission.READ_CONTACTS")
            if(status == PackageManager.PERMISSION_GRANTED){
                // ์ฃผ์†Œ๋ก ๋ชฉ๋ก ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ€๊ธฐ
                val intent = Intent(Intent.ACTION_PICK,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI)
                requestActivity.launch(intent)
            }else{
                permissionLauncher.launch("android.permission.READ_CONTACTS")
            }
        }
    }
}


๊ฐค๋Ÿฌ๋ฆฌ ์•ฑ

  • ์•”์‹œ์  ์ธํ…ํŠธ๋กœ ๊ฐค๋Ÿฌ๋ฆฌ ์•ฑ์˜ ์ด๋ฏธ์ง€ ๋ชฉ๋ก ํ™”๋ฉด์„ ์ถœ๋ ฅํ•ด๋ณด์ž!
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "image/*"
requestActivity.launch(intent) 
  • ์ด๋ฏธ์ง€ ํŒŒ์ผ์˜ ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ํฌ๋ฉด OOM (OutOfMemory Exception)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ, BitmapFactory.Options ๊ฐ์ฒด์˜ inSampleSize ๊ฐ’์œผ๋กœ ๋ฐ์ดํ„ฐ ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์—ฌ์„œ ๋กœ๋”ฉํ•ด์•ผ ํ•œ๋‹ค.
val option = BitmapFactory.Options() 
option.inSampleSize = 5 
  • ๊ฐค๋Ÿฌ๋ฆฌ ์•ฑ์˜ ContentProvider๊ฐ€ ์ œ๊ณตํ•˜๋Š” InputStream ๊ฐ์ฒด ํš๋“
  • InputStream ๊ฐ์ฒด์— ๋„˜์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋น„ํŠธ๋งต ๊ฐ์ฒด ์ƒ์„ฑ
var inputStream = contentResolver.openInputStream(it.data!!.data!!)
val bitmap = BitmapFactory.decodeStream(inputStream, null, option) 

์‹ค์Šต ์˜ˆ์ œ

package com.tutorial.c64

import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Bundle
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val imageView = findViewById<ImageView>(R.id.image_view)
        val button = findViewById<Button>(R.id.button)

        val launcher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) {
            try {
                val option = BitmapFactory.Options()
                option.inSampleSize = 5

                // ์ปจํ…์ธ  ํ”„๋กœ๋ฐ”์ด๋”์—๊ฒŒ ์ œ๊ณต๋ฐ›์€ ์‹๋ณ„์ž ๊ฐ’์œผ๋กœ ๋น„ํŠธ๋งต ๊ฐ์ฒด ์ƒ์„ฑ
                val inputStream = contentResolver.openInputStream(it.data!!.data!!)
                val bitmap = BitmapFactory.decodeStream(inputStream, null, option)
                inputStream!!.close()

                bitmap?.let {
                    imageView.setImageBitmap(bitmap) // ์ด๋ฏธ์ง€ ์„ค์ •
                } ?: let {
                    Toast.makeText(this, "์ด๋ฏธ์ง€ ๋กœ๋”ฉ ์‹คํŒจ", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        button.setOnClickListener {
            val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
            intent.type = "image/*"
            launcher.launch(intent) // ์•”์‹œ์  ์ธํ…ํŠธ๋กœ ๊ฐค๋Ÿฌ๋ฆฌ ์•ฑ ๋„์šฐ๊ธฐ
        }
    }
}


์ „ํ™” ์•ฑ

  • ์•”์‹œ์  ์ธํ…ํŠธ์˜ ์•ก์…˜ ๋ฌธ์ž์—ด์„ Intent.ACTION_CALL๋กœ ์ง€์ •
  • ์•”์‹œ์  ์ธํ…ํŠธ์˜ data ์ธ์ž URL์€ tel:๋กœ ์„ ์–ธ, ๊ทธ ๋’ค์— ์ „ํ™”๋ฒˆํ˜ธ ๋ช…์‹œ

์‹ค์Šต ์˜ˆ์ œ

<uses-permission android:name="android.permission.CALL_PHONE"/>
package com.tutorial.c65

import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val editView = findViewById<EditText>(R.id.editView)
        val button = findViewById<Button>(R.id.button)

        val permissionLauncher = registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ){ isGranted ->
            if(isGranted){
                val intent = Intent(Intent.ACTION_CALL,
                    Uri.parse("tel:${editView.text}"))
                startActivity(intent) // ์•”์‹œ์  ์ธํ…ํŠธ๋กœ ์ „ํ™” ์•ฑ ๋„์šฐ๊ธฐ 
            }else{
                Toast.makeText(this, "denied", Toast.LENGTH_SHORT).show()
            }
        }

        button.setOnClickListener {
            val status = ContextCompat.checkSelfPermission(this,
            "android.permission.CALL_PHONE")
            if(status == PackageManager.PERMISSION_GRANTED){
                val intent = Intent(Intent.ACTION_CALL,
                    Uri.parse("tel:${editView.text}"))
                startActivity(intent)
            }else{ // ํผ๋ฏธ์…˜ ์žฌ์š”์ฒญ 
                permissionLauncher.launch("android.permission.CALL_PHONE")
            }
        }
    }
}


์นด๋ฉ”๋ผ ์•ฑ

์นด๋ฉ”๋ผ ์•ฑ์„ ์—ฐ๋™ํ•˜์—ฌ ์‚ฌ์ง„์„ ์ดฌ์˜ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋Œ๋ ค๋ฐ›๋Š” ๋ฐฉ๋ฒ•์—๋Š” 2๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • ์‚ฌ์ง„ ๋ฐ์ดํ„ฐ ํš๋“ ๋ฐฉ๋ฒ•
  • ํŒŒ์ผ ๊ณต์œ  ๋ฐฉ๋ฒ•

์‚ฌ์ง„ ๋ฐ์ดํ„ฐ ํš๋“ ๋ฐฉ๋ฒ•

  • ์ดฌ์˜ํ•œ ์‚ฌ์ง„์„ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋„˜๊ฒจ๋ฐ›๋Š” ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ์˜ ํฌ๊ธฐ๊ฐ€ ์ž‘๋‹ค.
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
requestActivity.launch(intent)
val bitmap = it.data?.getExtras()?.get("data") as Bitmap 

ํŒŒ์ผ ๊ณต์œ  ๋ฐฉ๋ฒ•

  • ์•ฑ์—์„œ ์‚ฌ์ง„์„ ์ €์žฅํ•  ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.
  • ํŒŒ์ผ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜์—ฌ ์•”์‹œ์  ์ธํ…ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์นด๋ฉ”๋ผ ์•ฑ์„ ์‹คํ–‰ํ•œ๋‹ค.
  • ์นด๋ฉ”๋ผ ์•ฑ์—์„œ ์‚ฌ์ง„ ์ดฌ์˜ ํ›„, ์ดฌ์˜๋œ ์ด๋ฏธ์ง€๋ฅผ ๊ณต์œ ๋œ ํŒŒ์ผ์— ์ €์žฅํ•œ๋‹ค.
  • ์นด๋ฉ”๋ผ ์•ฑ์ด ์ข…๋ฃŒ๋˜๋ฉด์„œ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์•ฑ์—์„œ ํŒŒ์ผ์„ ์ฝ์–ด ์นด๋ฉ”๋ผ ์•ฑ์ด ์ €์žฅํ•œ ์‚ฌ์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

FileProvider

  • ์•ฑ๊ณผ ์•ฑ ๊ฐ„์— ํŒŒ์ผ์„ ๊ณต์œ ํ•  ๋•Œ๋Š” FileProvider๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค.
  • ์ด๋ฅผ ์œ„ํ•ด์„œ ๊ณต์œ ํ•˜๊ณ ์ž ํ•˜๋Š” ํŒŒ์ผ์˜ Uri ๊ฐ’์„ ์ค€๋น„ํ•ด์•ผ ํ•œ๋‹ค.
  • res/xml/file_paths.xml ํŒŒ์ผ์— ํ•ด๋‹น ๋‚ด์šฉ ๋“ฑ๋ก

  • ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์—์„œ provider์˜ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ๋กœ file_paths.xml ์ •๋ณด ๋“ฑ๋ก

  • ์ดฌ์˜๋œ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํŒŒ์ผ ์ƒ์„ฑ

  • ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ณต์œ ๋ฅผ ์œ„ํ•ด Uri ๊ฐ์ฒด ์ƒ์„ฑ ํ›„, ํ•ด๋‹น ์ •๋ณด๋ฅผ ์ธํ…ํŠธ์˜ ๋ถ€๊ฐ€ ๋ฐ์ดํ„ฐ๋กœ ์„ค์ •

  • ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ decodeFile() ํ•จ์ˆ˜์— ์ง€์ •ํ•˜์—ฌ Bitmap ๊ฐ์ฒด ํš๋“
val bitmap = BitmapFactory.decodeFile(filePath, option)

์‹ค์Šต ์˜ˆ์ œ

res/xml/file_path.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="myfiles"
        path="Android/data/com.tutorial.c66/files/Pictures"/>
</paths>

๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์— FileProvider ๋“ฑ๋ก

  • ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ์— file_path.xml ์ •๋ณด ๋“ฑ๋ก
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorial.c66">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidLab">

        <provider
            android:authorities="com.tutorial.c66.fileprovider"
            android:name="androidx.core.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path"/>
        </provider>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.cardview.widget.CardView
        android:layout_width="150dp"
        android:layout_height="150dp"
        app:cardCornerRadius="75dp"
        app:cardElevation="5dp">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop" />
    </androidx.cardview.widget.CardView>

    <Button
        android:id="@+id/dataButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="data" />

    <Button
        android:id="@+id/fileButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="file" />

</LinearLayout>

MainActivity

package com.tutorial.c66

import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val imageView = findViewById<ImageView>(R.id.imageView)
        val dataButton = findViewById<Button>(R.id.dataButton)
        val fileButton = findViewById<Button>(R.id.fileButton)

        val launcher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ){
            // ๋ถ€๊ฐ€ ๋ฐ์ดํ„ฐ๋กœ๋ถ€ํ„ฐ ๋น„ํŠธ๋งต ๊ฐ์ฒด ํš๋“
            val bitmap = it.data?.extras?.get("data") as Bitmap
            bitmap.let{
                imageView.setImageBitmap(bitmap)
            }
        }

        dataButton.setOnClickListener {
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) // ์ด๋ฏธ์ง€ ์บก์ณ ์•ก์…˜
            launcher.launch(intent) // ์•”์‹œ์  ์ธํ…ํŠธ๋กœ ์นด๋ฉ”๋ผ ์•ฑ ๋„์šฐ๊ธฐ
        }

        var filePath = ""
        val fileLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ){
            // ์ด๋ฏธ์ง€ ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ๋น„ํŠธ๋งต ๊ฐ์ฒด ์ƒ์„ฑ
            val option = BitmapFactory.Options()
            option.inSampleSize = 3
            val bitmap = BitmapFactory.decodeFile(filePath, option)
            bitmap?.let {
                imageView.setImageBitmap(bitmap)
            }
        }

        fileButton.setOnClickListener {
            val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
            val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
            val file = File.createTempFile(
                "JPEG_${timeStamp}_",
                ".jpg",
                storageDir
            )
            filePath = file.absolutePath // ํŒŒ์ผ ๊ฒฝ๋กœ๋ช… ์„ค์ •
            val uri = FileProvider.getUriForFile(
                this,
                "com.tutorial.c66.fileprovider",
                file
            )

            // ์•”์‹œ์  ์ธํ…ํŠธ์˜ ๋ถ€๊ฐ€ ๋ฐ์ดํ„ฐ๋กœ ํŒŒ์ผ uri ๋“ฑ๋กํ•˜๊ณ  ์นด๋ฉ”๋ผ ์•ฑ ๋„์šฐ๊ธฐ
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
            fileLauncher.launch(intent)
        }
    }
}

profile
์Šต๊ด€์ด ๋  ๋•Œ๊นŒ์ง€ ๐Ÿ“

0๊ฐœ์˜ ๋Œ“๊ธ€