브로드캐스트 리시버

<동적 권한 요청>

private fun requestSinglePermission(permission: String) { // 한번에 하나의 권한만 요청하는 예제
        if (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) // 권한 유무 확인
            return
        val requestPermLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { // 권한 요청 컨트랙트
            if (it == false) { // permission is not granted!
// 사용자가 요청 거부했을 경우 처리
            }
        }
        if (shouldShowRequestPermissionRationale(permission)) { // 권한 설명 필수 여부 확인
// 다이얼로그 등으로 사용자에게 권한 필요한 이유 설명
        } else {
// should be called in onCreate()
            requestPermLauncher.launch(permission) // 권한 요청 시작
        }
    }
inner class MyBroadcastReceiver : BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            // TO DO SOMTHING
            when(intent?.action){
                Intent.ACTION_POWER_CONNECTED -> {}
                else -> { }
            }
        }

    }
override fun onStart() {
        super.onStart()
        val ifilter = IntentFilter()
        ifilter.addAction(Intent.ACTION_POWER_CONNECTED)
        ifilter.addAction("MY Broadcast Msg")
        registerReceiver(myBroadcastReceiver, ifilter)
    }

    override fun onStop() {
        super.onStop()
        unregisterReceiver(myBroadcastReceiver)
    }
  • 시스템이나 다른 앱이 방송하는 메시지를 받는 리시버
  • 시스템 이벤트시 방송
    • 시스템 부트 완료, 충전 시작, 네트워크 연결 변경, 문자 수신 등의 이벤트
    • 문자 수신과 같은 민감한 정보는 권한을 필요로 함
  • 사용 방법
    • BroadcastReceiver 상속한 클래스, onReceive() 재정의
    • registerReceiver()로 1번의 클래스 객체 등록
    • 더 이상 수신할 필요가 없을 때 unregisterReceiver() 호출

Content Provider

  • 다른 앱에 데이터를 제공해주기 위해 표준화된 인터페이스
  • 적절한 데이터 은닉과 보호 기능을 제공

Content Resolver

val button2 = findViewById<Button>(R.id.button2)
        button2.setOnClickListener {
           if(checkSelfPermission(Manifest.permission.READ_CALL_LOG)== PackageManager.PERMISSION_GRANTED){
               val cursor = contentResolver.query(
                   CallLog.Calls.CONTENT_URI,
                   arrayOf(CallLog.Calls._ID, CallLog.Calls.NUMBER),
                   null,
                   null,
                   null
               )
               val idxWord = cursor?.getColumnIndex(CallLog.Calls.NUMBER)?:0
               val str = java.lang.StringBuilder()
               while(cursor?.moveToNext() == true){
                   str.append(cursor.getString(idxWord))
               }
               cursor?.close()
               textView.text = str
           }
        }

cursor = query(
	android.net.Uri uri, // Content URI
	String[] projection, // 가져올 테이블의 컬럼 이름
	String selection, // 조건, SQL의 WHERE 절과 비슷
	String[] selectionArgs, // selection의 ?에 들어갈 인자
	String sortOrder) // SQL의 ORDER BY에 해당
cursor.moveToNext() // 다음 로그 작업 수행
컬럼 인덱스 = cursor.getColumnIndex(컬럼 이름)
cursor.getString(컬럼 인덱스), cursor.getLong(컬럼 인덱스)
  • ContentProvider에 접근하기 위한 방법
  • CRUD- CREATE, READ, UPDATE, DELETE
  • 사용 방법(데이터 읽기, Retrieve)
    • Context에서 ContentResolver 객체 가져오기
    • query로 컨텐트 URI와 조건 등을 명시해서 실행, cursor 리턴
    • cursor를 사용하여 데이터 읽기
  • 데이터 Create Update Delete는 query대신 insert, update, delete를 사용

Content URI

if(checkSelfPermission(Manifest.permission.READ_CALL_LOG)== PackageManager.PERMISSION_GRANTED){
               val cursor = contentResolver.query(
                   CallLog.Calls.CONTENT_URI,
                   arrayOf(CallLog.Calls._ID, CallLog.Calls.NUMBER),
                   null,
                   null,
                   null
               )
               val idxWord = cursor?.getColumnIndex(CallLog.Calls.NUMBER)?:0
               val str = java.lang.StringBuilder()
               while(cursor?.moveToNext() == true){
                   str.append(cursor.getString(idxWord))
               }
               cursor?.close()
               textView.text = str
           }
  • query, insert, update, delete 모두 첫 번째 인자가 Content URI
  • Content URI는 접근하려는 content provider의 주소
    • content://제공자의이름/테이블경로 와 같은 형태
      • CallLog.Calls.CONTENT_URI
      • MediaStore.Images.Media.EXTERNAL_CONTENT_URI

+ Recent posts