4대 컴포넌트
브로드캐스트는 단어 그대로 방송을 하는 것이다. 방송의 특징을 생각해 보면 방송국은 불특정 다수에게 송신을 하고 필요한 사람은 수신하는 구조이다. 경우에 따라서 특정 사람에게만 송신되는 경우(ex. IPTV 가입자)도 있다. 안드로이드도 이와 별반 다를 것이 없다. (네트워크 분야에도 유니캐스트/멀티캐스트/브로드캐스트가 존재하는데 개념 자체는 매우 흡사하다.)
단말기의 상태 변화나 다른 앱이 송신하는 방송에 귀를 기울이고 있으면 여러 현상에 대한 처리가 가능하다. 예를 들면 배터리 상태가 15% 이하가 되면 절전모드에 들어가도록 할 수 있다.
이때 방송에 귀 기울이고 있는 수신자가 바로 브로드캐스트 리시버(BroadcastReceiver)이다. 브로드캐스트 리시버는 크게 두 가지 방법으로 다룰 수 있다. 바로 코드 레벨과 AndroidManifest를 통해서이다.
또한 수신만 가능한 것이 아니라 필요에 의해 방송도 가능하다. 이때 실제 방송에서 채널에 해당하는 것이 action이다. 예를 들어 KBS가 7번 채널이라면 배터리 상태 확인에 대한 action은 ACTION_BATTERY_CHANGED이다.
방송은 항상 송신되고 있지만 가입한 상품에 따라 수신할 수 있는 채널의 종류가 다르듯이 수많은 브로드캐스트 중에서 어떤 것을 수신할 것인지 등록하는 과정이 필요하다. 방법은 실제 방송의 채널에 해당하는 action 중 수신을 원하는 action을 IntentFilter를 통해 지정할 수 있다.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_SCREEN_ON);
위와 같이 ACTION_BATTERY_CHANGED, ACTION_SCREEN_ON를 등록하면 채널 2개짜리 상품에 가입한 것이다. 그렇다면 2개의 채널 중 실제 내가 시청하고 싶은 채널을 고르는 방법은 뭘까? 그건 바로 브로드캐스트 리시버의 onReceive() 메서드를 통해서 가능하다.
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
Toast toast = Toast.makeText(context, "Battery status is changed.", Toast.LENGTH_LONG);
toast.show();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Toast toast = Toast.makeText(context, "Screen on.", Toast.LENGTH_LONG);
toast.show();
}
}
비유하자면 BroadcastReciver라는 안테나에 수신된 전파는 최종적으로 onReceiver()라는 셋톱박스로 들어오는 것이다. onReceiver()에서 원하는 action에 대한 처리를 하면 되는 것이다.
코드 레벨이 아닌 AndroidManifest에서 브로드캐스트 리시버를 사용하는 것의 차이는 바로 filter의 등록 방법의 차이다. BroadcastReceiver를 상속받은 class는 receiver가 되어 filter.addAction()을 통해 수신할 action을 지정한 것을 하기와 같이 AndroidManifest에 바로 적용할 수 있다.
<receiver android:name=".BroadCastReceiverUsingManifest">
<intent-filter>
<action android:name="example.test.broadcast"></action>
</intent-filter>
</receiver>
방송을 보내는 방법은 매우 간단하다.
Intent intent = new Intent();
intent.setAction("example.test.broadcast");
sendBroadcast(intent);
인텐트를 하나 선언하고 나만의 채널(action)을 만들면 된다. 그 후 sendBroadcast()라는 메서드에 intent를 인자로 넘겨주면 끝이다. 이 방송을 수신하기 위해서는 자신이 선언한 action값을 정확히 filter에 등록해야 한다. 특정 패키지에만 전달하려면 Intent에 setPackage()를 이용해서 수신할 패키지를 설정하면 된다.
이를 바탕으로 간단한 예제를 만들어 볼 수 있다. 하기 예제는 배터리 상태 변화 및 화면 켜짐에 대한 정보를 수신하고 해당 변화 감지 시 토스트 메시지를 보여준다. 또한 버튼을 누르면 example.test.broadcast 라는 action으로 브로드캐스트를 한다. 이 역시 수신하면 토스트 메시지를 보여준다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.broadcastreceiverexample.mystoryg.broadcastreceiverexample.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BroadCastReceiver using java code and manifest" />
<Button
android:id="@+id/send_broadcast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Broadcast" />
</LinearLayout>
MainActivity.java
package com.broadcastreceiverexample.mystoryg.broadcastreceiverexample;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
BroadcastReceiver br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
Toast toast = Toast.makeText(context, "Battery status is changed.", Toast.LENGTH_LONG);
toast.show();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Toast toast = Toast.makeText(context, "Screen on.", Toast.LENGTH_LONG);
toast.show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button send = (Button) findViewById(R.id.send_broadcast);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("example.test.broadcast");
sendBroadcast(intent);
}
});
}
@Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(br, filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(br);
}
}
BroadCastReceiverUsingManifest.java
package com.broadcastreceiverexample.mystoryg.broadcastreceiverexample;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class BroadCastReceiverUsingManifest extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("example.test.broadcast")) {
Toast.makeText(context, "Customize broadcast!", Toast.LENGTH_LONG).show();
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.broadcastreceiverexample.mystoryg.broadcastreceiverexample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BroadCastReceiverUsingManifest">
<intent-filter>
<action android:name="example.test.broadcast"></action>
</intent-filter>
</receiver>
</application>
</manifest>