バインドを利用したservice

バインドを利用しない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>

タイトルとURLをコピーしました