システム全体にかかわる情報は「BroadcastIntent」という特殊なIntentを使って、 全てのアプリケーションに向けて発信される[7]。
BroadcastIntentには以下のようなものがある。
android.intent.action.TIME_TICK 時刻が変化した(分単位) android.intent.action.ACTION_POWER_CONNECTED 電源接続、 android.intent.action.ACTION_POWER_DISCONNECTED 電源切断、 android.intent.action.ACTION_SHUTDOWN シャットダウン、 android.net.wifi.WIFI_STATE_CHANGED ネットワーク状態が変わった
まず、記事[7]に倣って次のコードを試した。
// BroadcastReceiver
private BroadcastReceiver mReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 受信する情報の種類を設定
// 電源接続・切断の通知を受け取る
IntentFilter filter = new IntentFilter();
filter.addAction( Intent.ACTION_POWER_CONNECTED );
filter.addAction( Intent.ACTION_POWER_DISCONNECTED );
// 受信した場合の処理の記述
mReceiver = new BroadcastReceiver(){
@Override
public void onReceive( Context context, Intent intent ){
// Toast で受信内容を確認
Toast.makeText(context, "Receive broadcast:" + intent.getAction(),
Toast.LENGTH_LONG ).show();
}
};
// BroadcastReceiverを登録する
this.registerReceiver( mReceiver, filter );
}
@Override
public void onDestroy(){
super.onDestroy();
// 終了時に、BroadcastReceiverを登録解除する
this.unregisterReceiver( mReceiver );
}
よくある記事は一つのアプリ内での Service から Activity へ broadcast である[1]。 このレベルは難しくない。今回は、アプリAとアプリBがあって、 アプリBは Service でそのスレッドからアプリAの Activity に broadcast したい。
似たことを試みたが制約にかかりうまくいかなかった。
まず、記事[1]を二つのアプリに分けてテストする。
以下のプログラムにより、アプリ B の Service からアプリ A の Activity に情報(この場合は文字列)を送れる ことを確認した。
[アプリA]
public class MainActivity extends AppCompatActivity {
TextView my_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
my_view = findViewById(R.id.my_view);
UpdateReceiver receiver = new UpdateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("DO_ACTION");
registerReceiver(receiver, filter);
}
class UpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
Bundle extras = intent.getExtras();
String msg = extras.getString("message");
my_view.setText(msg);
Log.i("Received", msg);
}
}
}
[アプリB]
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
Button btn = new Button(this);
btn.setText("start");
ll.addView(btn);
setContentView(ll);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent service = new Intent(getApplicationContext(), MyService.class);
startService(service);
}
});
}
}
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
public int onStartCommand(Intent intent, int flags, int startId){
sendMessage("こんにちは");
stopSelf();
return START_NOT_STICKY;
}
protected void sendMessage(String msg){
Intent broadcast = new Intent();
broadcast.putExtra("message", msg);
broadcast.setAction("DO_ACTION");
getBaseContext().sendBroadcast(broadcast);
}
}
マニフェストによる方法を見かけたので、やってみたが、ダメだった。 android:exported="true" でもダメだった。 どこかに誤まりがあるのか、それとも仕様が変わったのかは分からない。
<receiver android:name=".MainActivity$UpdateReceiver" android:exported="false">
<intent-filter>
<action android:name="DO_ACTION"/>
</intent-filter>
</receiver>
自作地図アプリで位置情報取得を行っているが、電池消費量を抑えるために、別アプリとしてコントロールしたい。
少なくとも同一アプリでは、Location オブジェクトをそのまま broadcast できるが、ここでは、文字列として送る。
static final String ACTION_BROADCAST = "com.example.gps.broadcast";
static final String EXTRA_LOCATION = "com.example.gps.location";
protected void sendLocation(Location location) {
Intent broadcast = new Intent();
broadcast.putExtra(EXTRA_LOCATION, Utils.getLocationText(location));
broadcast.setAction(ACTION_BROADCAST);
getBaseContext().sendBroadcast(broadcast);
}
static String getLocationText(Location location) {
return location == null ? "Unknown location" :
"(" + location.getLatitude() + ", " + location.getLongitude() + ")";
}
以下のプログラムにより、同一アプリでの受信を確認した。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String ACTION_BROADCAST = "com.example.gps.broadcast";
MyReceiver myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_BROADCAST);
registerReceiver(myReceiver, filter);
startService(new Intent(MainActivity.this, LocationUpdatesService.class));
}
// Receiver for broadcasts sent by LocationUpdatesService.
private class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String msg = extras.getString("com.example.gps.location");
Log.d("GPS", msg);
}
}
}
以下のプログラムにより、別アプリ(テスト用でこの受信だけのアプリ AppA)での受信を確認した。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UpdateReceiver receiver = new UpdateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.gps.broadcast");
registerReceiver(receiver, filter);
}
class UpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
Bundle extras = intent.getExtras();
String msg = extras.getString("com.example.gps.location");
Log.i("Received", msg);
}
}
}
自作地図アプリはすでにかなり大きいプログラムになっている。 現在は内部サービスからの broacast を MainActivity ではなく、GPSLogger extends AppCompatActivity で受けている。
まず、この GPSLogger で受けることを考え、次のようにしたが、受信できなかった。
public class GPSLogger extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String ACTION_BROADCAST = "com.example.gps.broadcast";
MyReceiver myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_BROADCAST);
registerReceiver(myReceiver, filter);
}
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String msg = extras.getString("com.example.gps.location");
Log.d("GPS", msg);
}
}
}
そこで MainActivity に移動させた。今度は受信するようになった。
public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
// 省略
MyReceiver myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.gps.broadcast");
registerReceiver(myReceiver, filter);
}
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String msg = extras.getString("com.example.gps.location");
Log.d("GPS", msg);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
}