-
Intent + broadcastAndroid 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() 메서드가 다시 콜백을 등록해 줘서 결과값을 받아온다.
- Activity는 앱 안의 단일 화면을 나타냅니다.
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()에 전달하면 됩니다.
- 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메서드를 사용해서 구현할 경우
- A -> B 실행, 메모리가 부족해서 A가 소멸됨.
- B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
- A가 소멸됐다가 다시 생성돼서 B에게 결과값을 요청한 줄 모름.
ActivityResultLauncher객체와 registerForActivityResult()를 사용한 경우
- A -> B 실행, 메모리가 부족해서 A가 소멸됨.
- B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
- 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 - 액티비티 시작