ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Intent + broadcast
    Android 2023. 3. 24. 16:04

    https://developer.android.com/guide/components/intents-filters?hl=ko

    Intent

    인텐트가 구성 요소 사이의 통신을 촉진하는 데는 여러 가지 방식이 있지만 기본적인 사용 사례는 크게 세 가지로 나눌 수 있습니다.

    • 액티비티 시작
      • Activity는 앱 안의 단일 화면을 나타냅니다.
        Activity의 새 인스턴스를 시작하려면 Intent를 startActivity()로 전달하면 됩니다.
        Intent는 시작할 액티비티를 설명하고 모든 필수 데이터를 담습니다.
        액티비티가 완료되었을 때 결과를 수신하려면, startActivityForResult()를 호출합니다.
        액티비티는 해당 결과를 이 액티비티의 onActivityResult() 콜백에서 별도의 Intent 객체로 수신합니다.
      • startActivityForResult()는 deprecated! 
        ->  ActivityResultLauncher와 registerForActivityResult()로 대체
        https://developer.android.com/training/basics/intents/result?hl=ko

        AndroidX Activity와 Fragment에 도입된 Activity Result API 사용을 적극 권장.
        결과를 얻는 Activity를 실행하는 로직을 사용할 때, 메모리 부족으로 인해 프로세스와 Activity가 사라질 수 있다. (특히 카메라 같은 메모리를 많이 사용하는 작업은 소멸 확률이 굉장히 높다.)

        -> 따라서 Activity Result API는 다른 Activity를 실행하는 코드는 Result Callback 부분과 분리해서 만들어야 한다.
        Result Callback은 프로세스와 Activity가 다시 생성될 때 사용할 수 있어야 하므로 다른 Activity를 실행하는 로직은 Activity가 생성될 때마다 Callback을 무조건 등록해야 한다.

        예를들어서,
        A 액티비티와 B 액티비티가 있을 때,

        startActivityResult메서드와 onActivityResult메서드를 사용해서 구현할 경우

        A -> B 실행, 메모리가 부족해서 A가 소멸됨.
        B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
        A가 소멸됐다가 다시 생성돼서 B에게 결과값을 요청한 줄 모름.
        ActivityResultLauncher객체와 registerForActivityResult()를 사용한 경우

        A -> B 실행, 메모리가 부족해서 A가 소멸됨.
        B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
        A가 다시 생성돼도 registerForActivityResult() 메서드가 다시 콜백을 등록해 줘서 결과값을 받아온다.

    registerForActivityResult

    val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
        // Handle the returned Uri
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
    
        val selectButton = findViewById<Button>(R.id.select_button)
    
        selectButton.setOnClickListener {
            // Pass in the mime type you'd like to allow the user to select
            // as the input
            getContent.launch("image/*")
        }
    }

    ,ActivityResultRegistry를 직접 사용하여 ActivityResultCaller를 구현하지 않는 별도의 클래스에서 활동 결과를 수신

    class MyLifecycleObserver(private val registry : ActivityResultRegistry)
            : DefaultLifecycleObserver {
        lateinit var getContent : ActivityResultLauncher<String>
    
        override fun onCreate(owner: LifecycleOwner) {
            getContent = registry.register("key", owner, GetContent()) { uri ->
                // Handle the returned Uri
            }
        }
    
        fun selectImage() {
            getContent.launch("image/*")
        }
    }
    
    class MyFragment : Fragment() {
        lateinit var observer : MyLifecycleObserver
    
        override fun onCreate(savedInstanceState: Bundle?) {
            // ...
    
            observer = MyLifecycleObserver(requireActivity().activityResultRegistry)
            lifecycle.addObserver(observer)
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            val selectButton = view.findViewById<Button>(R.id.select_button)
    
            selectButton.setOnClickListener {
                // Open the activity to select an image
                observer.selectImage()
            }
        }
    }
    • 서비스 시작
      • Service는 사용자 인터페이스 없이 백그라운드에서 작업을 수행하는 구성 요소입니다. Android 5.0(API 레벨 21) 이상부터는 JobScheduler로 서비스를 시작할 수 있습니다. Android 5.0(API 레벨 21) 이하 버전은 Service 클래스의 메서드를 사용하면 서비스를 시작할 수 있습니다. 서비스를 시작하여 일회성 작업을 수행하도록 하려면(예: 파일 다운로드) Intent를 startService()에 전달하면 됩니다. Intent는 시작할 서비스를 설명하고 모든 필수 데이터를 담고 있습니다.서비스가 클라이언트-서버 인터페이스로 디자인된 경우, 다른 구성 요소로부터 서비스에 바인딩하려면 Intent를 bindService()에 전달하면 됩니다.

    • 브로드캐스트 전달
      • 브로드캐스트는 모든 앱이 수신할 수 있는 메시지입니다. 시스템은 시스템이 부팅될 때 또는 기기가 충전을 시작할 때 등 시스템 이벤트에 대한 다양한 브로드캐스트를 전달합니다. Intent를 sendBroadcast() 또는 sendOrderedBroadcast()에 전달하면 다른 앱에 브로드캐스트를 전달할 수 있습니다.

    A 액티비티와 B 액티비티가 있을 때,

    startActivityResult메서드와 onActivityResult메서드를 사용해서 구현할 경우

    1. A -> B 실행, 메모리가 부족해서 A가 소멸됨.
    2. B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
    3. A가 소멸됐다가 다시 생성돼서 B에게 결과값을 요청한 줄 모름.

    ActivityResultLauncher객체와 registerForActivityResult()를 사용한 경우

    1. A -> B 실행, 메모리가 부족해서 A가 소멸됨.
    2. B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
    3. A가 다시 생성돼도 registerForActivityResult() 메서드가 다시 콜백을 등록해 줘서 결과값을 받아온다.
    • 명시적 인텐트
      • 수신 액티비티의 컴포넌트 이름(클래스 이름)을 참조하여 특정 액티비티의 시작을 요청할때 사용한다. (보통 인텐트라고 하면 명시적 인텐트를 의미한다.) 
      • 새로운 인텐트 인스턴스를 생성하여 요청 (시작 액티비티의 context와 목표 컴포넌트의 이름을 생성자 인자로 전달한다.)
    // 기본형태
    val intent = Intent(this,MainActivity::class.java)
    startActivity(intent)
    
    //데이터 추가시
    intent.putExtra("String","문자열")
    intent.putExtra("Int",12345)
    
    
    //수신시
    val extras = intent.extras ?: return
    val myString = extras.getString("String")
    val myInt = extras.getInt("Int")

    • 암시적 인텐트
      • 수행할 액션과 처리할 데이터 타입을 지정한다. 수신 액티비티(특정 액티비티에 가지 않고 특정 액션만 수행하기도 한다.)를 지정하지 않고, 알아서 수신자를 찾아서 시행된다.
      • 수신 액티비티가 2개 이상일 경우, 사용자가 액티비티를 선택하게 해준다. -> Intent Resolution, 지도를 실행하는 경우 - 구글 지도, 네이버 지도, 카카오 지도 등
      • 인텐트 필터
        • Manifest에서 액티비티 내부에서 intent-filter를 지정해준다.
    //인텐트 필터
    <activity android:name=".DetailActivity" android:exported="false">
        <intent-filter>
            <action android:name="kr.co.lee.ACTION_VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="http" />
        </intent-filter>
    </activity>
    
    //인텐트 사용 가능 여부 확인
    fun isIntentAvailable(context:Context,action:String):Boolean{
    	val packageManager = context.packageManager
        val intent = Intent(action)
        val list = packageManager.queryIntentActivities(intent,
        PackageManager.MATCH_DEFAULT_ONLY)
        return list.size>0
    }
    • 브로드 캐스트 인텐트
      • 브로드캐스트를 통해서 전파되는 Intent 객체
      • 컴포넌트 간의 메시징과 이벤트 시스템 제공 + 이벤트 발생을 알려 주기 위해서 안드로이드 시스템이 사용함.
      • 생성시 액션 문자열을 포함하고, 데이터와 카테고리 문자열을 추가로 포함 할 수 있다.

     

    val intent = Intent()
    intent.action = "com.example.BroadCast"
    intent.putExtra("MyData",100)
    //안드로이드 3.0 버전 이상에서는 아래 코드 추가
    // intent.flags = Intent.FLAG_INCLUDE_STOPPED_PACKAGES  ->사용정지된 앱의 컴포넌트를 시작시키는 것이 인텐트에 허용된다.
    sendBroadCast(intent)
    • 브로드 캐스트 수신자 : BroadCastReceiver 클래스로 부터 상속 받고 onReceive()를 오버라이딩하여 구현함.
      • 어떤 이벤트가 발생했을때 시스템이 메세지를 보내서 앱의 모든 리시버에 알리고 리시버는 그중 등록된 액션의 브로드 캐스트만 받게된다.
      • Manifest나 코드상에서 등록해야 한다.
      • 수신자는 리스닝 하는 특정 브로드캐스트 인텐트를 나타내는 액션 문자열을 인텐트 필터에 정의한다. 이와 일치하는 인텐트가 감지될 경우 해당 브로드캐스트 수신자가 호출된다.
    //브로드캐스트 리시버
    private const val TAG = "MyBroadcastReceiver"
    
    class MyBroadcastReceiver : BroadcastReceiver() {
    //브로드캐스트를 받을경우 실행할 코드
        override fun onReceive(context: Context, intent: Intent) {
            StringBuilder().apply {
                append("Action: ${intent.action}\n")
                append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n")
                toString().also { log ->
                    Log.d(TAG, log)
                    Toast.makeText(context, log, Toast.LENGTH_LONG).show()
                }
            }
        }
    }
    
    
    //Manifest에서 이를 등록, 핸드폰의 부팅 완료시 구동할 브로드캐스트 리시버, 안드로이드 8.0 이전버전!!!!!
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    
    <receiver android:name=".MyBroadcastReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    
    //코드에서 동적으로 등록하기, 
    //Android 9.0 이상에서는 IntentFilter 객체를 생성후 Activity에서 RegisterReceiver()를 호출하여 등록해야 한다.
    val broadCastScreenOn = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            // 화면이 켜지면 수행될 코드 작성
        }
    
    }
    //해지 시에는 unregisterReceiver(receiver)로 해지한다.
    val screenOnIntentFilter = IntentFilter(Intent.ACTION_SCREEN_ON)
    registerReceiver(broadCastScreenOn, screenOnIntentFilter)

     

    예시, 

     

    메인 액티비티에서 브로드캐스트 인텐트를 생성하고 전송하기

    //메인 액티비티 내에서
    
    
    fun broadcastIntent(view:View){
    	val intent = Intent()
        //수신자 액티비티의 인텐트 필터에서는  "com.example.sendbroadcast" 과 같은 action 요소가 정의되어야 한다.
        intent.action = "com.example.sendbroadcast" -> 따로 지정하는 액션 문자열
        intent.flags = Intent.FLAG_INCLUDE_STOPPED_PACKAGE
        sendBroadcast(intent)
    }

    브로드캐스트 수신자

    class MyReceiver : BroadcastReceiver(){
    	override fun onReceive(context:Context,intent:Intent){
        	Toast.makeText(context,"브로드캐스트 수신",Toast.LENGTH_LONG).show()
        }
    
    }

    브로드 캐스트 수신자 등록하기

    //메인 액티비티 내에서
    
    var receiver : BroadCastReceiver?=null
    
    private fun configureReceiver(){
    	val filter = IntentFilter()
        filter.addAction("com.exaple.sendbroadcast")
        receiver = MyReceiver()
        registerReceiver(receiver,filter)
    
    }
    
    override fun onDestroy(){
    	super.onDestroy()
        unregisterReceiver(receiver)
    }

     

     

     

    https://developer.android.com/guide/components/broadcasts?hl=ko


    +브로드캐스트 

    'Android' 카테고리의 다른 글

    Service  (0) 2023.03.25
    Coroutine  (0) 2023.03.24
    context  (0) 2023.03.24
    4대 컴포넌트와 매니페스트  (0) 2023.03.20
    WorkManager & AlarmManager  (1) 2023.03.20

    댓글

Designed by Tistory.