LocalBroadcastManager

2013-07-19T00:00:00+00:00 Android Java

※ローカルのネタ帳からのほぼコピペ

一言で言えばアプリ内ローカルでのみ利用可能なブロードキャスト的な感じかなと。一般的には

<receiver android:name=".SampleBroadcastReceiver">
  <intent-filter>
    <action android:name="sample.test.broadcast" />
  </intent-filter>
</receiver>

的な感じでグローバルなBroadcastReceiverを設定するんだと思うけど、これでやると

adb shell am broadcast -a sample.test.broadcast

等でも反応できちゃう。特に必要性が無い場合とかであったりだとかの場合とかだとLocalBroadcastManagerを使ってアプリ内のコンテキストのみでブロードキャスト可能にしたり出来るとか。説明ムズイ

とりまぁやってみる。要件的には

  • Activity(LocalBroadcastManager#registerReceiver)
  • Service(LocalBroadcastManager#sendBroadcast)
  • BroadcastReceiver(Handler#sendMessage)
  • Activity(Handler#handleMessage)

っていう流れだけ。

SampleService.java

package sample.test;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;

public class SampleService extends Service {

    private LocalBroadcastManager mBroadcast;
    private Timer timer = null;

    @Override
    public void onCreate() {
        super.onCreate();
        mBroadcast = LocalBroadcastManager.getInstance(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        sendBroadcast("--- START ---");

        timer = new Timer();
        timer.schedule(
            new TimerTask() {
                @Override
                public void run() {
                    sendBroadcast(new Date().toString());
                }
            },
            0,
            10000
        );

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        sendBroadcast("--- STOP ---");

        super.onDestroy();
        timer.cancel();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void sendBroadcast(String message) {
        Intent intent = new Intent(SampleBroadcastReceiver.ACTION);
        intent.putExtra("message", message);

        mBroadcast.sendBroadcast(intent);
    }
}

SampleBroadcastReceiver.java

package sample.test;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.text.TextUtils;

public class SampleBroadcastReceiver extends BroadcastReceiver {

    public static final String ACTION = "sample.test.broadcast";
    private Handler mHandler;

    public SampleBroadcastReceiver(Handler handler) {
        this.mHandler = handler;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (mHandler == null) {
            return;
        }

        if (intent.hasExtra("message")) {
            String message = intent.getStringExtra("message");

            if (!TextUtils.isEmpty(message)) {
                mHandler.sendMessage(
                    mHandler.obtainMessage(0, message)
                );
            }
        }
    }
}

MainActivity.java

package sample.test;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getName();
    private BroadcastReceiver mBroadcast;

    private static EditText mText;

    private static final Handler sHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String str = (String)msg.obj;

            if (TextUtils.isEmpty(str)) {
                return;
            }

            mText.append(str + "rn");
        }

    };

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        mText = (EditText)findViewById(R.id.logs);
        mBroadcast = new SampleBroadcastReceiver(sHandler);

        ((Button)findViewById(R.id.start)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                startService(new Intent(MainActivity.this, SampleService.class));
            }
        });

        ((Button)findViewById(R.id.stop)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(new Intent(MainActivity.this, SampleService.class));
            }
        });
    }

    @Override
    public void onResume() {
        Log.v(TAG, "onResume");

        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(
            mBroadcast,
            new IntentFilter(SampleBroadcastReceiver.ACTION)
        );
    }

    @Override
    public void onPause() {
        Log.v(TAG, "onPause");

        super.onPause();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcast);
        stopService(new Intent(this, SampleService.class));
    }
}

終わり。実行してServiceを起動してほっとくと

っつー感じに。LocalBroadcastManagerでregisterReceiverをしたBroadcastReceiverは

adb shell am broadcast -a sample.test.broadcast

的なので要求を出しても反応しない。

<receiver android:name=".SampleBroadcastReceiver">
  <intent-filter>
    <action android:name="sample.test.broadcast" />
  </intent-filter>
</receiver>

的な事をすれば上記コマンドで反応させる事は出来る。という事で意図しないブロードキャストを許容しないのであればLocalBroadcastManagerを使ったブロードキャストな設計を組み込むべきというオチで

ちなみに以下を参考にした方が良いという。今までなんだったんだと..orz

参考: http://stackoverflow.com/questions/8802157/how-to-use-localbroadcastmanager/8875292

Laravel使ってみた (12) - LaravelでCSRF - ActionsContentView