Android BroadCast

노력을 즐기는 사람·2020년 12월 7일
0

손자취 앱개발

목록 보기
3/4

앱을 개발하면서 서비스를 구현하고 있는데 Broadcast, Reciver, PendingIntent를 사용하게 되었다. 이것에 대해 정리해보자

Broadcast

안드로이드는 broadcast 메세지를 안드로이드 시스템, 앱 내/외부와 주고 받을 수 있다. 그리고 이런 로직을 정의하는 것이 우리의 역할이다.
앱에 특정 broadcast에 대한 receive들을 정의할 수 있다. receive를 정의해두고 broadcast 메세지를 날리면 os가 자동으로 broadcast들을 receive들에게 라우팅해준다.

broadcast 메시지는 action 문자열로 구분되어 있는Intetnt 객체에 포함되어 전달된다. 물론 Intent에 여러가지 추가 정보를 넣을 수 있다. bundle에 넣어서 전달하자.

Receiving broadcasts

broadcast를 받는 것은 2가지 방법이 있다. manifest에 정의되어 있는 receiver로 받거나 context에서 등록된 receiver로 받는 방법이 있다.

manifest-declared receivers

manifest에서는 아래와 같이 등록하자.

<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
    </intent-filter>
</receiver>

그리고 다음 java 코드도 필요하다. 손자취 앱은 이 방식을 선택했다.

public class MyBroadcastReceiver extends BroadcastReceiver {
        private static final String TAG = "MyBroadcastReceiver";
        @Override
        public void onReceive(Context context, Intent intent) {
            StringBuilder sb = new StringBuilder();
            sb.append("Action: " + intent.getAction() + "\n");
            sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
            String log = sb.toString();
            Log.d(TAG, log);
            Toast.makeText(context, log, Toast.LENGTH_LONG).show();
        }
    }

시스템 패키지 매니저는 receiver를 앱이 설치 되는 시점에 등록한다. 이를 통해 앱이 실행되고 있지 않더라도 receiver를 통해 앱을 실행할 수 있는 entry point가 된다고 한다.
시스템은 각 broadcast 마다 BroadcastReceiver를 생성해준다고 한다.

Context-registered receivers

일단 BroadcastReceiver 인스턴스를 생성한다.
BroadcastReceiver br = new MyBroadcastReceiver();

IntentFilter를 생성하고 registerReceiver()를 호출하여 recevier를 등록한다.

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);

context-registered 방식을 취하면 broadcast를 등록한 context가 살아있을 때마 수신할 수있다. 그러니까 앱이 종료되면 broadcast를 받을 수 없다.

unregisterReceiver() 메소드를 호출하여 broadcast를 그만 받을 수 있다.

Effects on process state

BroadcastReceiver는 실행중이던 실행중이지않던 자신이 포함하고 있는 프로세스의 state에 영향을 받는다. 그래서 시스템에 의해 종료될 수 있다. 예를들어 프로세스가 receiver를 실행시키면 이녀석은 foreground 프로세스로 간주된다. 그래서 메모리가 부족하면 시스템에 의해 종료된다.

그렇기 때문에 많은 작업 시간이 필요한 작업을 broadcast receiver에서 백그라운드 스레드를 실행시키지 말자 동작을 수행하다가 프로세스가 죽으면 안되니까.
그리고 이를 방지하기 위해서는 goAsync() 메소드를 사용하거나 JobService, JobScheduler를 활용하여 스케쥴링을하자.

아래의 코드를 참고하자. 손자취 앱에서도 AsyncTask를 활용하여 SQLite 로직을 처리했다.

public class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        final PendingResult pendingResult = goAsync();
        Task asyncTask = new Task(pendingResult, intent);
        asyncTask.execute();
    }

    private static class Task extends AsyncTask<String, Integer, String> {

        private final PendingResult pendingResult;
        private final Intent intent;

        private Task(PendingResult pendingResult, Intent intent) {
            this.pendingResult = pendingResult;
            this.intent = intent;
        }

        @Override
        protected String doInBackground(String... strings) {
            StringBuilder sb = new StringBuilder();
            sb.append("Action: " + intent.getAction() + "\n");
            sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
            String log = sb.toString();
            Log.d(TAG, log);
            return log;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            // Must call finish() so the BroadcastReceiver can be recycled.
            pendingResult.finish();
        }
    }
}

sending broadcast

3가지 방법을 통해 broadcast를 보낼 수 있다.

  • sendOrderedBroadcast()
  • sendBroadcast()
  • LocalBroadcastManager.sendBroadcast()
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("data","Notice me senpai!");
sendBroadcast(intent);

손자취 앱의 경우 PendingIntentgetBroadcast()메소드를 통해 boradcast를 등록하고 notifiation에 발행해서 전송했다.

profile
노력하는 자는 즐기는 자를 이길 수 없다

0개의 댓글