Android Kotlin : Volumn Up/Down Listener in Fragment - LocalBroadcast
LocalBroadcast 를 사용하여 Fragment에서 키 이벤트를 처리하는 방법
에 대해 소개합니다.
방송(Broadcast) 이란?
라디오 방송(Broadcast)는 FM 대역으로 변조된 음성신호를 송신 안테나를 통해 송출하는 것을 의미합니다. 이 때 안테나를 통해 전달되는 신호는 목적지가 없습니다. 특정 FM 라디오를 듣고 싶은 사람은 라디오 기기에서 원하는 방송의 FM주파수로 튜닝해서 방송을 들을 수 있습니다.
Broadcast in Android
안드로이드에서 방송(Boardcast)라 함은 불특정 다수를 대상으로 신호를 전달하고, 특정 앱에서 원하는 내용만 필터링해서 원하는 신호를 받을 수 있습니다. 라디오에서는 MBC, KBS 등의 방송국에서 방송을 송출합니다. 안드로이드에서는 안드로이드 시스템(OS) 또는 앱에서 방송을 할 수 있습니다.
부팅이 완료되거나, 이어폰이 연결되거나, 잠금화면이 해재되는 등의 이벤트가 발생하면 안드로이드 시스템에서 해당 이벤트가 발생하였다는 사실을 방송합니다. 이런 이벤트 알림이 필요한 앱은 브로드캐스트 리시버(Broadcast Reciever)를 등록 후 원하는 신호만 필터링 해서 그 방송을 수신 할 수 있습니다.
Global Broadcast, Local Broadcast
방송(Broadcast)에는 Global Broadcast와 Local Broadcast가 있습니다. Global Broadcast는 안드로이드 시스템에서 하는 방송, Local Broadcast 는 앱에서 하는 방송으로 쉽게 이해해도 됩니다.
- Global Broadcast
- 안드로이드 시스템에서 Broadcast Reciever가 등록된 앱에 전달하는 방송
- 부팅 완료, USB 장치 연결 등 OS의 이벤트에 따라 동적인 기능을 수행해야 하는 경우 사용
- Local Broadcast
- (앱에서 방송)현재 실행되고 있는 앱(프로세스)만 전달 하는 Broadcast 입니다.
- Activity에서 Service등의 컴포넌트에 데이터 또는 작업 요청 상태를 보내는 경우 사용
이번 포스트는 Local Broadcast 만 다룹니다.
Local Broadcast
송신측
Broadcast를 송신하기 위해 아래와 같이 Intent를 생성 후 LocalBroadcastManager 객체의 sendBroadcast 메서드 인자에 입력합니다. 방송을 하게 되는 컨텐츠가 Intent입니다. 즉, Intent의 ACTION이름과 putExtra() 로 등록된 Key-Data 의 데이터가 전달됩니다.
- BROADCAST_ACTION : 필터링할 ACTION 이름(문자열)로 사용자 임의 지정
val intent = Intent(BROADCAST_ACTION).apply { putExtra("Status", 0) }
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
수신측
Broadcast를 수신 후 이벤트를 처리하기 위해 아래의 순서를 진행합니다.
1. Broadcast Receiver 객체 생성
BroadcastReceiver() 객체에 방송을 수신했을 떄 수행될 코드를 작성합니다. onReceive 메서드는 Ctrl + O 를 눌러 오버라이드 할 수 있습니다.
val statusReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.getIntExtra("Status", -1)) {
// When the volume down button is pressed, simulate a shutter button click
0 -> {
// "Status" 값으로 0이 수신된 경우
}
1 -> {
// "Status" 값으로 1이 수신된 경우
}
}
}
}
2. Broadcast Receiver 객체를 브로드캐스트 리시버에 등록
Activity의 경우 onCreate 메서드 내에, Fragment인 경우 onViewCreated 메서드에 등록하면 됩니다. 브로드캐스트 리시버를 등록할 때 Intent Filter를 함께 등록 합니다.
localBraodcastManager = LocalBroadcastManager.getInstance(view.context)
val filter = IntentFilter().apply { addAction(BROADCAST_ACTION) }
localBraodcastManager.registerReceiver(statusReceiver, filter)
3. (필요시)브로드캐스트 리시버 수신 종료
필요시, 액티비티 또는 프래그먼트가 종료될 때 브로드캐스트 리시버가 동작하지 않도록 아래의 코드를 추가합니다. 프래그먼트의 경우 onDestroy() 메서드에 코드를 추가하면 됩니다.
localBraodcastManager.unregisterReceiver(statusReceiver)
프레그먼트에서 볼륨키 이벤트 처리
액티비티에서 볼륨키와 같은 키이벤트를 처리는 onKeyDown() 콜백 함수로 쉽게 구현 가능합니다. 프래그먼트 클래스는 onKeyDown() 함수를 지원하지 않습니다. 프래그먼트에서 키 이벤트를 구현하기 위해 Activity의 onKeyDown() 콜백함수에서 특정 키 이벤트가 발생하면 입력된 키가 무엇인지 방송을 하고, 프래그먼트에 브로드캐스트 리시버를 등록해서 키 이벤트를 처리하는 예시입니다.
새로운 프로젝트를 생성하고, 프래그먼트를 1개 추가하고 아래와 같이 코드를 작성합니다.
activity_main.xml
UI가 중요한 부분이 아니니, 간단히 작성하였습니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/fragment"
android:name="com.blacklog.boradcastreceiver.Fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment.xml
UI가 중요한 부분이 아니니, 간단히 작성하였습니다.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment"
android:gravity="center"/>
</FrameLayout>
MainActivity.kt
onKeyDown() 콜백함수에서 볼륨 다운, 볼륨 업 키가 눌러지면 해당 KEY CODE를 Broadcast 합니다.
package com.blacklog.boradcastreceiver
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.KeyEvent
import androidx.localbroadcastmanager.content.LocalBroadcastManager
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
return when(keyCode) {
KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP -> {
val intent = Intent("key_event_action").apply { putExtra("key_event_extra", keyCode) }
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
true
}
else -> super.onKeyDown(keyCode, event)
}
}
}
Fragment.kt
Fragment에 키 이벤트를 수신하는 Broadcast Reciever 를 등록합니다. 볼륨 업키가 눌러지면 "volumeDownKey Pressed", 볼륨 다운키가 눌러지면 "volumeDownKey Pressed" 토스트 메세지를 출력합니다.
package com.blacklog.boradcastreceiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.view.KeyEvent
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
class Fragment : Fragment() {
private lateinit var broadcastManager: LocalBroadcastManager
private val volumeDownReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.getIntExtra("key_event_extra", KeyEvent.KEYCODE_UNKNOWN)) {
KeyEvent.KEYCODE_VOLUME_DOWN -> {
Toast.makeText(context, "volumeDownKey Pressed", Toast.LENGTH_SHORT).show()
}
KeyEvent.KEYCODE_VOLUME_UP -> {
Toast.makeText(context, "volumeUpKey Pressed", Toast.LENGTH_SHORT).show()
}
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
broadcastManager = LocalBroadcastManager.getInstance(view.context)
val filter = IntentFilter().apply { addAction("key_event_action") }
broadcastManager.registerReceiver(volumeDownReceiver, filter)
}
override fun onDestroy() {
super.onDestroy()
broadcastManager.unregisterReceiver(volumeDownReceiver)
}
}
실행 결과
위 코드를 실행하면 아래 그림과 같이 프래그먼트에 등록된 브로드캐스트 리시버가 정상적으로 동작하는 것을 확인 할 수 있습니다.
끝까지 읽어 주셔서 감사합니다.^^
'Programming > Android App(Kotlin)' 카테고리의 다른 글
웹에서 코틀린 프로그래밍 언어 연습 및 학습 하는 방법 - try.kotlinlang.org (1) | 2021.05.05 |
---|---|
안드로이드 코틀린 : 동영상 촬영 후 외부저장소(앱 디렉토리)에 저장하고 미리보기 with FileProvider (3) | 2021.05.04 |
안드로이드 코틀린 : 액티비티에서 볼륨 업/다운 키 이벤트 등록 - onKeyDown() 콜백 함수 (0) | 2021.04.27 |
안드로이드 코틀린 : Pair, Triple, Data Class 여러 개의 반환 값을 가지는 메서드 또는 함수 만들기 (0) | 2021.04.21 |
안드로이드 코틀린 : 여러 개의 버튼 리스너 한 번에 처리하기 View.OnClickListener (0) | 2021.04.19 |