Bound Service的三种方式(Binder、 Messenger、 AIDL)

参考google的官方文档:http://developer.android.com/guide/components/bound-services.html

首先要明白需要的情景,然后对三种方式进行选择:

(一)可以接收Service的信息(获取Service中的方法),但不可以给Service发送信息

Extending the Binder class If your service is private to your own application and runs in the same process as the client (which is common), you should create your interface by extending 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 either the  Binder  implementation(得到Service对象,从而获取Service中的方法) or even the  Service . This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not create your interface this way is because your service is used by other applications or across separate processes.
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中的方法。因为利用Message,所以不用担心并发

Using a Messenger
If you need your interface to work across different processes, you can create an interface for the service with a  Messenger. In this manner, the service defines a  Handler that responds to different types of  Message objects. This  Handler is the basis for a  Messenger that can then share an  IBinder with the client, allowing the client to send commands to the service using  Message objects. Additionally, the client can define a  Messenger of its own so the service can send messages back.

This is 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 communication (IPC) without the need to use AIDL.

Here's a summary of how to use a Messenger:

In this way, there are no "methods" for the client to call on the service. Instead, the client delivers "messages" (Message objects) 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的比较:

Compared to AIDL

When you need to perform IPC, using a Messenger for your interface is simpler than implementing it with AIDL, because Messenger queues all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the service, which must then handle multi-threading.

For most applications, the service doesn't need to perform multi-threading, so using a Messengerallows the service to handle one call at a time. If it's important that your service be multi-threaded, then you should use AIDL to define your interface.


Binding to a Service


Application components (clients) can bind to a service by calling bindService(). The Android system then calls the service's onBind() method, which returns an IBinder for interacting with the service.

The binding is asynchronous. bindService() returns immediately and does not return the IBinder to the client. To receive the IBinder, the client must create an instance of ServiceConnection and pass it to bindService(). The ServiceConnection includes a callback method that the system calls 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 purely a bound service—the Android system manages it for you based on whether it is bound to any clients.

However, if you choose to implement the onStartCommand() callback method, then you must explicitly stop the service, because the service is now considered to be started. In this case, the service runs until the service stops itself with stopSelf() or another component calls stopService(), regardless of whether it is bound to any clients.

Additionally, if your service is started and accepts binding, then when the system calls your onUnbind()method, you can optionally return 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() callback. 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 applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by  implementing a Binder  or, if you want to perform IPC, but do  not  need to handle multithreading, implement your interface  using a Messenger
  1. Create the .aidl file

    This file defines the programming interface with method signatures.

  2. Implement the interface

    The Android SDK tools generate an interface in the Java programming language, based on your .aidl file. This interface has an inner abstract class named Stub that extends Binder and implements methods from your AIDL interface. You must extend the Stub class and implement the methods.

  3. Expose the interface to clients

    Implement a Service and override onBind() to return your implementation of the Stub class.

IRemoteService.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)的IRemoteService.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;
}


AIDLService.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
			
		}
	   
	};

}

AIDLActivity.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;
		
	}

}
AIDLActivity Toast一个“0”,为AIDLService中getPid return 的"0"。

下面介绍如何传递对象。

Passing Objects over IPC




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值