バインドを利用しないserviceもありますが、serviceは勝手に動き続けるか、自動的に停止するようにするかになります。
実際にはバインドを利用してserviceが起動している時にもアクションを連携できるようにしないと使い道は少なくなってしまいます。
アクティビティとsrvcie間で利用するにはaidlファイルを作成し、インターフェイスを記載しておく必要があります。
バインドするまでの流れ
1.(アクティビティ)bindServiceメソッドを実行
※BIND_AUTO_CREATEを設定
2.(service)onCreate実行
3.(service)onBind実行で、serviceのAIDLオブジェクトをリターン。
4.(アクティビティ)onServiceConnected実行。
引数にあるIBinderから、serviceのAIDLオブジェクトが取得でき、serviceにアクセスできるようになります。
5.(アクティビティ)serviceのAIDLインターフェイスで作成したstartService実行しアクティビティのAIDLオブジェクトを渡す。
6.(serivce)アクティビティのAIDLオブジェクトを受け取り、アクティビティにアクセスできるようになる。
・・・(任意のやりとり)・・・
7.(アクティビティ)serviceのAIDLインターフェイスで作成したendService実行し、servcieの終了処理実行。
8.(アクティビティ)unbindService実行でバインドも終了。
ServiceConnectionインターフェイスを実装したコネクションを、アクティビティからservcieにbindServiceメソッドで渡します。serviceではonBindでservcieのAIDLオブジェクトを返します。その後アクティビティではserviceのAIDLオブジェクトを利用して、アクティビティのAIDLオブジェクトを渡します。
2重のやりとりが行われた後に初めて相互に連携するので、ややこしくてしかたありません。
サービスにはAndroidManifest.xmの登録が必要です。
ソース
com/neko/mytimer/MytimerActivity.java
package com.neko.mytimer;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MytimerActivity extends Activity {
private MyServiceAIDL bindserviceIf = null;
private MyConnection conn =null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btnstart = (Button)findViewById(R.id.btnstart);
btnstart.setOnClickListener(new startListener());
Button btnend = (Button)findViewById(R.id.btnend);
btnend.setOnClickListener(new endListener());
}
class startListener implements OnClickListener{
public void onClick(View v) {
Intent intent = new Intent(MyServiceAIDL.class.getName());
conn=new MyConnection();
//1.バインド
bindService(intent, conn, BIND_AUTO_CREATE);
}
}
class endListener implements OnClickListener{
public void onClick(View v) {
try {
bindserviceIf.endService(bindactibityIf);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(conn);
}
}
//ServiceConnectionの実装
class MyConnection implements ServiceConnection{
//4.onServiceConnected
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
bindserviceIf = MyServiceAIDL.Stub.asInterface(arg1);
try {
//5.サービスのADILオブジェクトを使ってアクティビティのAIDLオブジェクトを渡す
bindserviceIf.startService(bindactibityIf);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName arg0) {
try {
bindserviceIf.endService(bindactibityIf);
} catch (RemoteException e) {
e.printStackTrace();
}
bindserviceIf = null;
}
}
//アクティビティのADILオブジェクトの実装
private MytimerActivityAIDL bindactibityIf = new MytimerActivityAIDL.Stub() {
public void displayTime(String spantime) throws RemoteException {
handler.sendMessage(Message.obtain(handler,0,spantime));
}
};
//スレッドなのでhanlderを使用
private Handler handler = new Handler(){
public void handleMessage(Message msg){
TextView tv =(TextView)findViewById(R.id.textview1);
tv.setText((String)msg.obj);
}
};
}
com/neko/mytimer/MytimerActivityAIDL.aidl
package com.neko.mytimer;
interface MytimerActivityAIDL {
void displayTime(String spantime);
}
com/neko/mytimer/MyService.java
package com.neko.mytimer;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService extends Service{
private Timer timer=null;
private MytimerActivityAIDL callback =null;
private int counter = 0;
//2.onCreateはonBindの前に呼ばれる
@Override
public void onCreate(){
super.onCreate();
timer = new Timer();
timer.schedule(task,1000,1000);
}
//3.onBindで、servcieのAIDLオブジェクトをリターンしている。
@Override
public IBinder onBind(Intent intent) {
if(MyServiceAIDL.class.getName().equals(intent.getAction())){
return serviceIf;
}
return null;
}
@Override
public boolean onUnbind(Intent intent){
timer.cancel();
timer.purge();
return super.onUnbind(intent);
}
//serviceのAIDLの実装
private MyServiceAIDL.Stub serviceIf = new MyServiceAIDL.Stub() {
//6.startServiceの引数でアクティビティのAIDLオブジェクトを受信
public void startService(MytimerActivityAIDL callback)
throws RemoteException {
MyService.this.callback = callback;
}
public void endService(MytimerActivityAIDL callback) throws RemoteException {
MyService.this.callback=null;
}
};
private TimerTask task = new TimerTask() {
@Override
public void run() {
counter += 1;
try {
//アクティビティのADILオブジェクトを使っている
callback.displayTime(counter+"秒");
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
}
com/neko/mytimer/MyServiceAIDL.aidl
package com.neko.mytimer;
import com.neko.mytimer.MytimerActivityAIDL;
interface MyServiceAIDL {
void startService(MytimerActivityAIDL callback);
void endService(MytimerActivityAIDL callback);
}
main.xml(レイアウト)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textview1"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="0"
android:textSize="46px"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<Button
android:id="@+id/btnstart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btnstart"
/>
<Button
android:id="@+id/btnend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btnend"
/>
</LinearLayout>
</LinearLayout>
AndroidMAnifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.neko.mytimer"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MytimerActivity"
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="MyService">
<intent-filter>
<action
android:name="com.neko.mytimer.MyServiceAIDL"/>
</intent-filter>
</service>
</application>
</manifest>
