Bound Serviceの3つの方式(Binder、Messenger、AIDL)

20999 ワード

googleの公式文書を参照してください。http://developer.android.com/guide/components/bound-services.html
まず必要なシーンを理解して、三つの方法を選択します。
(一)Serviceの情報は受信できますが、Serviceに情報を送信することはできません。
Extensding the Binder class
If your service is prvate to your own aplication and runs in the same process as the client(which is comon)、you shound create your interface by extens the  Binder class and returning an instance of it from  onBind().The client receives the  Binder and can use it to directly access public methods available in eigther the  Binder implemenation(Serviceオブジェクトを取得し、Serviceでのメソッドを取得する)or even the  Service..。
This the preferred technique when your service is merrely a background workers for your own aplication.The only reason you would not create your interface is because beur service is byhers protectionation。
Serviceコードは以下の通りです。
package com.example.boundservice;

import java.util.Random;

import android.R.integer;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

public class LocalService extends Service {
	
	private IBinder myBinder = new MyBinder();

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return myBinder;
	}
	public class MyBinder extends Binder {
		 LocalService getService() {
	            return LocalService.this;
	        }
	}
	public int getRandomNumber() {
		return new Random().nextInt(100);
	}

}
Activityコードは以下の通りです。
package com.example.boundservice;

import com.example.boundservice.LocalService.MyBinder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.TextView;

public class BindingActivity extends Activity implements ServiceConnection{
	private LocalService localService;
	private MyBinder myBinder;
	boolean mBound = false;
	
	@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		super.onStart();
		Intent intent = new Intent(this,LocalService.class);
		bindService(intent, this, Context.BIND_AUTO_CREATE);
	}
	
	@Override
	protected void onStop() {
        super.onStop(); 
        // Unbind from the service
	    if (mBound) {
	    	unbindService(this);
	        mBound = false;
	    }
    }
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_binding_activity);
		findViewById(R.id.button_show_binding_text).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View arg0) {
				((TextView)findViewById(R.id.textview)).setText(""+localService.getRandomNumber());
			}
		});
	}
	
	@Override
	public void onServiceConnected(ComponentName arg0, IBinder arg1) {
		myBinder = (MyBinder)arg1;
		localService = myBinder.getService();
		mBound = true;
	}
	
	@Override
	public void onServiceDisconnected(ComponentName arg0) {
		 mBound = false;
	}
}
(二)Messengerを使ってServiceメッセージを受け取ることができますし、Serviceメッセージを送ることもできます。しかし、Serviceのメソッドを呼び出すことができませんでした。メッセンジャーを利用していますので、併発の心配はありません。
Using a Messenger If you need your interface to work acros different processes,you can create an interface for the service with a  Messenger.In this manner,the service defines a  Handler that reponds to different types of  Message object.This  Handler is the basis for a  Messenger that can then share an  IBinder with the client、allowing the client to send command to the service using  Message object.Additionally,the client can define a  Messenger of its own so the service can send messages back.
This the simplest way to perform interprocess communication(IPC)、because the  Messenger queues all requests into a single thread so that you don't have to design your service to be thread-safe.
If you need your service to communicate with remote processes,then you can use a  Messenger to provide the interface for your service.This technique allows you to perform interprocess comunication(IPC)without the need to use AIDL.
ヘレ's a summary of how to use a  Messenger
The service implements a  Handler that receives a calback for each call from a client.
  • The  Handler is used to create a  Messenger object(which is a reference to the  Handler).
  • The  Messenger creates an  IBinder that the service returns to clients from  onBind().Cients use the  IBinder トinstantiate the  Messenger (that references the service's  Handler)、which the client uses to send Message object to the service.The service receives each  Message in its  Handler—speciflially、in the  handleMessage() method.In this way,there are no“methods”for the client to call on the service.Instead,the client delivers“message”(Message) object)that the service receives in its  Handler.
    次のプログラムは二つの機能をテストしました。ActivityはServiceにメッセージを送ります。Serviceは一つのToastを生成します。ActivityはServiceにメッセージを送り、ServiceはActivityにもう一つのメッセージを返します。
    Serviceコードは以下の通りです。
    package com.example.boundservice;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.Messenger;
    import android.os.RemoteException;
    import android.widget.Toast;
    
    public class MessengerService extends Service {
    	static final int MSG_SAY_HELLO = 0;
    	static final int MSG_FROM_SERVICE_TO_ACTIVITY = 1;
    	
    	// step 1
    	class IncomingHandler extends Handler {
    		@Override
    		public void handleMessage(Message msg) {
    			// TODO Auto-generated method stub
    			switch (msg.what) {
    			case MSG_SAY_HELLO:
    				Toast.makeText(getApplicationContext(), "Service:Hello!", Toast.LENGTH_SHORT).show();
    				break;
    			// receive activity's message and send it back;
    			case MSG_FROM_SERVICE_TO_ACTIVITY:
    				Messenger activityMessenger = new Messenger(new MessengerActivity().new ActivityHandler());
    				try {
    					activityMessenger.send(Message.obtain(null,MessengerService.MSG_FROM_SERVICE_TO_ACTIVITY,0,0));
    				} catch (RemoteException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				break;
    			default:
    				super.handleMessage(msg);
    			}
    		}
    	}
    	// step 2
    	Messenger messenger = new Messenger(new IncomingHandler());
    	// step 3
    	@Override
    	public IBinder onBind(Intent arg0) {
    		// TODO Auto-generated method stub
    		return messenger.getBinder();
    	}
    	
    }
    
    Activityコードは以下の通りです。
    package com.example.boundservice;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    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.Messenger;
    import android.os.RemoteException;
    import android.util.Log;
    import android.view.View;
    import android.widget.Toast;
    
    public class MessengerActivity extends Activity implements ServiceConnection{
    	private Messenger messenger;
    	private Boolean mBound = false;
    	
    	@Override
    	protected void onStart() {
    		// TODO Auto-generated method stub
    		super.onStart();
    		bindService(new Intent(MessengerActivity.this,MessengerService.class),this, Context.BIND_AUTO_CREATE);
    	}
    	
    	@Override
    	protected void onStop() {
    		// TODO Auto-generated method stub
    		super.onStop();
    		if(!mBound) {
    			unbindService(this);
    		}
    	}
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_messenger_activity);
    		
    		//send message to service
    		findViewById(R.id.button_send_message_to_service).setOnClickListener(new View.OnClickListener() {
    			
    			@Override
    			public void onClick(View arg0) {
    				try {
    					// a message is a reference to the Handler
    					messenger.send(Message.obtain(null,MessengerService.MSG_SAY_HELLO,0,0));
    				} catch (RemoteException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				
    			}
    		});
    		
    		// send message to the service to trigger a message to be sent back;
    		findViewById(R.id.button_reveive_message_to_service).setOnClickListener(new View.OnClickListener() {
    			
    			@Override
    			public void onClick(View arg0) {
    				try {
    					// a message is a reference to the Handler
    					messenger.send(Message.obtain(null,MessengerService.MSG_FROM_SERVICE_TO_ACTIVITY,0,0));
    				} catch (RemoteException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		});
    	}
    	// A handler used to receive message from service
    	public class ActivityHandler extends Handler {
    		@Override
    		public void handleMessage(Message msg) {
    			// TODO Auto-generated method stub
    			if(msg.what == MessengerService.MSG_FROM_SERVICE_TO_ACTIVITY) {
    				Log.i("FFFF","Received Service's Message!");
    			}
    		}
    	}
    
    	@Override
    	public void onServiceConnected(ComponentName arg0, IBinder arg1) {
    		// a message is a reference to the Handler
    		// use a messenger to wrap the binder,so can we send the message to service
    		messenger = new Messenger(arg1);
    		mBound = true;
    	}
    
    	@Override
    	public void onServiceDisconnected(ComponentName arg0) {
    		mBound = false;
    		
    	}
    
    }
    
    MessengerとAIDLの比較:
    Compred to AIDL
    When you need to perform IPC,using a  Messenger for your interface is simpler than implement it with AIDL,because  Messenger queues all call to the service,whers,a pure AIDL interface sends simultianeous requests to the service,which must then handle multi-threading.
    For most appration s,the service doesn't need to perform multi-threading,so using a  Messenger allows the service to handle one call a a time.If it's import that your service be multi-threaded,then you shound use AIDL to define your interface.
    Binding to a Service
    Apple components can bind to a service by caling  bindService().The Android system then cals the service's  onBind() method,which returns an  IBinder for interacting with the service.
    The binding is asynchronous.  bindService() returns immediate y and does not return the  IBinder to the client.To receive the  IBinder,the client must create an instance of  ServiceConnection andパスit to  bindService().The  ServiceConnection includies a calback methat the system cals to deliver the  IBinder.
    Managing the Lifecycle of a Bound Service
    When a service is unbound from all clients,the Android system destroys it(unless it was also started with)  onStartCommand()).As such,you don't have to manage the lifecycle of your service if it's purey a bound service-the Android system mage it for you based on whethe it is bound to any clients.
    However,if you chose to implement the  onStartCommand() calback method、then you must explicitly stop the service、because the service is now consided to be started.In this case,the service runs until the service stops itself with  stopSelf() or another component cals  stopService(),regardless of whether it is bound to any clients.
    Additionally,if your service is started and accepts binding,then when the system call your  onUnbind() method,you can optionlyreturn  true if you would like to receive a call to  onRebind() the next time a client Binds to the service(instead of receiving a call to)  onBind()).  onRebind() returns void,but the client still receives the  IBinder in its  onServiceConnected() calback.Below,figure 1 illustrates the logic for this kind of lifecycle.
    (三)AIDLを使用する
     (1.IPCは不要です。implement a Binder;2.IPCが必要です。併発は不要です。use a Messenger;3.IPCが必要です。併発は必要です。AIDL)
    Using AIDL is necessary only if You allow clients from different appication s to access your service for IPC and want to handle multing in your service.If you dot need to perform concurrent IPC different。  implementing a Binder
     or、if you want to perform IPC、but do 
    not
     need to handle multihreading、implement your interface  using a Messenger
    ..。 
  • Create the.aidl file This file defines the programming interface with method signature.
  • Implement the interface The Android SDK tools generate an interface in the Java programming lagage,based on your  .aidl file.This interface has an inner abstract class named  Stub that extens  Binder and implements methods from your AIDL interface.You must exted the  Stub class and implement the methods.
  • Expose the interface to clients Implement a  Service and override  onBind() to return your implemention of the  Stub class.
  • IREE oteService.aidlファイル:
    // IRemoteService.aidl
    package com.example.boundservice;
    
    // Declare any non-default types here with import statements
    
    /** Example service interface */
    interface IRemoteService {
        /** Request the process ID of this service, to do evil things with it. */
        int getPid();
    
        /** Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);
    }
    自動生成(eclipse自動、studioはrebuildが必要です)のIreeoteService.java:
    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: /Users/Francis/Documents/workspace/BoundService/src/com/example/boundservice/IRemoteService.aidl
     */
    package com.example.boundservice;
    // Declare any non-default types here with import statements
    /** Example service interface */
    public interface IRemoteService extends android.os.IInterface
    {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.example.boundservice.IRemoteService
    {
    private static final java.lang.String DESCRIPTOR = "com.example.boundservice.IRemoteService";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.boundservice.IRemoteService interface,
     * generating a proxy if needed.
     */
    public static com.example.boundservice.IRemoteService asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.example.boundservice.IRemoteService))) {
    return ((com.example.boundservice.IRemoteService)iin);
    }
    return new com.example.boundservice.IRemoteService.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
    return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
    switch (code)
    {
    case INTERFACE_TRANSACTION:
    {
    reply.writeString(DESCRIPTOR);
    return true;
    }
    case TRANSACTION_getPid:
    {
    data.enforceInterface(DESCRIPTOR);
    int _result = this.getPid();
    reply.writeNoException();
    reply.writeInt(_result);
    return true;
    }
    case TRANSACTION_basicTypes:
    {
    data.enforceInterface(DESCRIPTOR);
    int _arg0;
    _arg0 = data.readInt();
    long _arg1;
    _arg1 = data.readLong();
    boolean _arg2;
    _arg2 = (0!=data.readInt());
    float _arg3;
    _arg3 = data.readFloat();
    double _arg4;
    _arg4 = data.readDouble();
    java.lang.String _arg5;
    _arg5 = data.readString();
    this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
    reply.writeNoException();
    return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
    }
    private static class Proxy implements com.example.boundservice.IRemoteService
    {
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote)
    {
    mRemote = remote;
    }
    @Override public android.os.IBinder asBinder()
    {
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor()
    {
    return DESCRIPTOR;
    }
    /** Request the process ID of this service, to do evil things with it. */
    @Override public int getPid() throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
    _reply.readException();
    _result = _reply.readInt();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    return _result;
    }
    /** Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    _data.writeInt(anInt);
    _data.writeLong(aLong);
    _data.writeInt(((aBoolean)?(1):(0)));
    _data.writeFloat(aFloat);
    _data.writeDouble(aDouble);
    _data.writeString(aString);
    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    }
    static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    /** Request the process ID of this service, to do evil things with it. */
    public int getPid() throws android.os.RemoteException;
    /** Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
    }
    
    AIDLNService.java:
    package com.example.boundservice;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    public class AIDLService extends Service {
    
    	@Override
    	public IBinder onBind(Intent arg0) {
    		// TODO Auto-generated method stub
    		return mBinder;
    	}
    	private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
    
    		@Override
    		public int getPid() throws RemoteException {
    			// TODO Auto-generated method stub
    			return 0;
    		}
    
    		@Override
    		public void basicTypes(int anInt, long aLong, boolean aBoolean,
    				float aFloat, double aDouble, String aString)
    				throws RemoteException {
    			// TODO Auto-generated method stub
    			
    		}
    	   
    	};
    
    }
    
    AIDLNActivity.java:
    package com.example.boundservice;
    
    import com.example.boundservice.IRemoteService.Stub;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.view.View;
    import android.widget.Toast;
    
    public class AIDLActivity extends Activity implements ServiceConnection{
    	
    	private Boolean mBound = false;
    	private IRemoteService iRemoteServe;
    	@Override
    	protected void onStart() {
    		// TODO Auto-generated method stub
    		super.onStart();
    		bindService(new Intent(AIDLActivity.this,AIDLService.class), this, Context.BIND_AUTO_CREATE);
    		
    	}
    	@Override
    	protected void onStop() {
    		// TODO Auto-generated method stub
    		super.onStop();
    		if(!mBound) {
    			unbindService(this);
    		}
    	}
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_aidl_activity);
    		findViewById(R.id.button_show_aidl_result).setOnClickListener(new View.OnClickListener() {
    			
    			@Override
    			public void onClick(View arg0) {
    				try {
    					Toast.makeText(getApplicationContext(), ""+iRemoteServe.getPid(), Toast.LENGTH_SHORT).show();
    				} catch (RemoteException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		});
    	}
    	@Override
    	public void onServiceConnected(ComponentName arg0, IBinder arg1) {
    		iRemoteServe = Stub.asInterface(arg1);
    		mBound = true;
    	}
    
    	@Override
    	public void onServiceDisconnected(ComponentName arg0) {
    		mBound = false;
    		
    	}
    
    }
    
    AIDLNActivity Toastの「0」は、AIDLNServiceのget Pid returnの「0」である。
    相手を伝える方法を紹介します。
    Passing Object over IPC