Serviceとブロードキャストするテスト


2014年4月23日現在、私が理解している内容です。
間違っている場合があります。


サービスからアクティビティに情報を送りたい

ブロードキャストというしくみを使うと、サービスからアクティビティに情報を渡すことができます。
Serviceとバインドするテスト」のコードを改造していきます。

まず、新規作成で、ブロードキャストレシーバを継承した新しいクラスを作ります。
「MyReceiver1」とします。


MyReceiver1.java

package com.example.test25; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; public class MyReceiver1 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); String message1 = bundle.getString("MyMessage"); //以上が必要な構文 //以下、動作確認用テスト MainActivity main = new MainActivity(); //メッセージをActivityに伝える main.ReceiveMessage1(message1); } }




MyServiceS1.javaを書き換える

次に、サービスの「MyServiceS1」から情報を送信する記述です。


Intent broadcastIntent = new Intent(); broadcastIntent.putExtra("MyMessage", "ブロードキャスト送信"); broadcastIntent.setAction("MyAction"); getBaseContext().sendBroadcast(broadcastIntent);


MyServiceS1.java

package com.example.test25; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.widget.Toast; public class MyServiceS1 extends Service { private final IBinder mBinder = new MyLocalBinder(); public class MyLocalBinder extends Binder { MyServiceS1 getService() { return MyServiceS1.this; } } @Override public int onStartCommand(Intent intent, int flags, int startId) { Intent broadcastIntent = new Intent(); broadcastIntent.putExtra("MyMessage", "ブロードキャスト送信"); broadcastIntent.setAction("MyAction"); getBaseContext().sendBroadcast(broadcastIntent); return START_STICKY; } @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } @Override public IBinder onBind(Intent arg0) { // TODO 自動生成されたメソッド・スタブ //(注意)必ず戻り値を指定すること return mBinder; } public void TestMessage1(String message1) { //トースト表示 Toast.makeText( getBaseContext(), message1, Toast.LENGTH_LONG).show(); } }





MainActivity.javaを書き換える

「MainActivity」で、以下の記述を追加していきます。
ブロードキャストレシーバの登録。


IntentFilter intentfilter; MyReceiver1 myreceiver;


myreceiver = new MyReceiver1(); intentfilter = new IntentFilter(); intentfilter.addAction("MyAction"); registerReceiver(myreceiver, intentfilter);


以上が必要な記述で、
こちらは、アクティビティ側が情報を受け取ったことを確認するためのテスト用コードです。


private static String ReceiveMessage1 = ""; public void ReceiveMessage1(String message1){ ReceiveMessage1 = message1; }


レシーバからの文字情報を、すぐにトーストとかで表示しようとするとエラーになるっぽいので、
Handlerのほうに処理を投げておきます。


countText1.setText(String.valueOf(count1) + " <" + ServiceName1 + "> " + CheckServiceRunning() + "\n" + ReceiveMessage1);


ReceiveMessage1は、「CLOSE」ボタンが押されたら、文字列を空にするようにします。


//CLOSEボタンが押されたかどうか監視する button2.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //サービスを終了させる stopService(new Intent(MainActivity.this, MyServiceS1.class)); ReceiveMessage1=""; } });



MainActivity.java

package com.example.test25; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningServiceInfo; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.graphics.Color; public class MainActivity extends Activity { IntentFilter intentfilter; MyReceiver1 myreceiver; //レシーバー private static String ReceiveMessage1 = ""; private MyServiceS1 mMyService1; //バインド private static final String ServiceName1 = MyServiceS1.class.getCanonicalName(); ListView setlistvw ; private Timer mainTimer; private MainTimerTask mainTimerTask; private TextView countText1; private int count1 = 0; private Handler Handler1 = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //-------------------------------------------------- //レイアウトを作る LinearLayout layout1 = new LinearLayout(this); layout1.setOrientation(LinearLayout.HORIZONTAL); //横に並べる //レイアウトの背景を緑にする layout1.setBackgroundColor(Color.argb(128, 0, 255, 0)); //----------------------------------------- //新しいボタンを作る Button button1 = new Button(this); button1.setText("OPEN"); layout1.addView(button1); Button button2 = new Button(this); button2.setText("CLOSE"); layout1.addView(button2); //---------------------------- //新しいボタンを作る Button button4 = new Button(this); //ボタンに文字を表示 button4.setText("BIND"); button4.setTextSize(10.0f); //ボタンをレイアウトに追加 layout1.addView(button4); //新しいボタンを作る Button button5 = new Button(this); //ボタンに文字を表示 button5.setText("START"); button5.setTextSize(10.0f); //ボタンをレイアウトに追加 layout1.addView(button5); //新しいボタンを作る Button button6 = new Button(this); //ボタンに文字を表示 button6.setText("STOP"); button6.setTextSize(10.0f); //ボタンをレイアウトに追加 layout1.addView(button6); //---------------------------- Button button3 = new Button(this); button3.setText("END"); //ボタンをレイアウトに追加 layout1.addView(button3); //----------------------------------------- //OPENボタンが押されたかどうか監視する button1.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //サービスを呼び出す startService(new Intent(MainActivity.this,MyServiceS1.class)); } }); //----------------------------------------- //CLOSEボタンが押されたかどうか監視する button2.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //サービスを終了させる stopService(new Intent(MainActivity.this, MyServiceS1.class)); ReceiveMessage1=""; } }); //----------------------------------------- //ENDボタンが押されたかどうか監視する button3.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //自分を終了させる finish(); } }); //----------------------------------------- //BINDボタンが押されたかどうか監視する button4.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //サービスに送信する mMyService1.TestMessage1("BIND情報伝達成功"); } }); //----------------------------------------- //STARTボタンが押されたかどうか監視する button5.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //バインド開始 Intent intent = new Intent(getApplicationContext(), MyServiceS1.class); bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE); } }); //----------------------------------------- //STOPボタンが押されたかどうか監視する button6.setOnClickListener( new OnClickListener() { //ボタンが押されたら何かする @Override public void onClick(View v) { //バインド終了 unbindService(mMyServiceConnection); } }); //----------------------------------------- //ブロードキャストレシーバの登録 myreceiver = new MyReceiver1(); intentfilter = new IntentFilter(); intentfilter.addAction("MyAction"); registerReceiver(myreceiver, intentfilter); //----------------------------------------- //リストビュー setlistvw = new ListView(this); LinearLayout layout2 = new LinearLayout(this); layout2.setOrientation(LinearLayout.VERTICAL); //縦に並べる countText1 = new TextView(this); layout2.addView(countText1); layout2.addView(layout1); layout2.addView(setlistvw); setContentView(layout2); //-------------------------------- //タイマー this.mainTimer = new Timer(); this.mainTimerTask = new MainTimerTask(); this.mainTimer.schedule(mainTimerTask, 0,100); //----------------------------------------- } //「ServiceName1」(MyServiceS1)のサービスが実行されてるかチェックする private boolean CheckServiceRunning() { checkServiceList1(); ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE); for (RunningServiceInfo info : services) { if (ServiceName1.equals(info.service.getClassName())) { return true; } } return false; } @Override protected void onResume() { super.onResume(); CheckServiceRunning(); } public void checkServiceList1(){ ArrayList<String> serviceList = new ArrayList<String>(); ActivityManager activityManager = (ActivityManager)getSystemService(ACTIVITY_SERVICE); // 起動中のサービス情報を取得 List<RunningServiceInfo> runningService = activityManager.getRunningServices(100); if(runningService != null) { for(RunningServiceInfo srvInfo : runningService) { serviceList.add(srvInfo.service.getShortClassName()); } } ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, serviceList); setlistvw.setAdapter(adapter); } public class MainTimerTask extends TimerTask { @Override public void run() { Handler1.post( new Runnable() { public void run() { count1 += 1; countText1.setText(String.valueOf(count1) + " <" + ServiceName1 + "> " + CheckServiceRunning() + "\n" + ReceiveMessage1); } }); } } //------------------------------------------------------------------ //バインド private ServiceConnection mMyServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //サービスと接続する手続き MyServiceS1.MyLocalBinder binder = (MyServiceS1.MyLocalBinder)service; mMyService1 = binder.getService(); } @Override public void onServiceDisconnected(ComponentName name) { //サービスと切断したとき } }; //-------------------------------------------------------------------- //レシーバーから情報を受け取る public void ReceiveMessage1(String message1){ ReceiveMessage1 = message1; } }





AndroidManifest.xmlの確認

レシーバの利用には、AndroidManifest.xmlに、次の記述が必要になります。

MyReceiver1をレシーバとして使う設定。


<receiver android:name="MyReceiver1"/>



<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test25" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.test25.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="MyServiceS1"/> <receiver android:name="MyReceiver1"/> </application> </manifest>






できあがり

「OPEN」ボタンを押すと、サービス開始と共に、「ブロードキャスト送信」と表示されます。
「CLOSE」ボタンで消えます。
その他のボタンを無造作に押すと落ちます。
Serviceとバインドするテスト」を参照。








その他いろいろ

あと、サービスを終了するときは、以下の終了手続きをしないと、ログにエラーが出力されます。
バインドされてないのに、終了手続きをしてもエラーになります。
ご注意ください。


@Override protected void onDestroy() { super.onDestroy(); unbindService(mMyServiceConnection); unregisterReceiver(myreceiver); }


「ReceiveMessage1()」で、トーストを表示しようとすると落ちるというのは、
MainActivityのインスタンスからコンテキストがうまく取得できないからでしょうか。
でも、よくみたら、「MyReceiver1」の、「onReceive」でコンテキストもインテントも取得できるじゃないですか。
というわけで、「ReceiveMessage1()」を、次のように変更すればトーストが表示できました。


public void ReceiveMessage2(Context context, Intent intent){ Bundle bundle = intent.getExtras(); String message1 = bundle.getString("MyMessage"); ReceiveMessage1 = message1; Toast.makeText(context, message1, Toast.LENGTH_LONG).show(); }















戻る