您的位置:首页 > 移动开发 > Android开发

Android FrameWork 之Binder机制初识

2014-01-10 17:04 381 查看
public class Binder extends Object implements IBinder

IBinder

为远程对象制定了基础的接口方法,轻量级进程内与进程间IPC调用的核心部分。该类为抽象类,并且android建议通过继承 Binder去实现接口,而不是直接的去实现IBinder接口。

IBinder的核心方法是:

public boolean transact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException;


它与Binder中的onTransact方法对应,它允许你使用IBinder(客户端)、Binder( 服务端 )交互。

并且当客户端执行完transact()方法后并不会立刻回调,而是等待 服务端 onTransact()执行完毕后才会回调。

/**
* Default implementation is a stub that returns false.  You will want
* to override this to do the appropriate unmarshalling of transactions.
*
* <p>If you want to call this, call transact().
*/
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (code == INTERFACE_TRANSACTION) {
reply.writeString(getInterfaceDescriptor());
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
String[] args = data.readStringArray();
if (fd != null) {
try {
dump(fd.getFileDescriptor(), args);
} finally {
try {
fd.close();
} catch (IOException e) {
// swallowed, not propagated back to the caller
}
}
}
// Write the StrictMode header.
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
return true;
}
return false;
}


例如,当进程A与进程B 通过IPC通讯。

进程A调用transact()方法,将Parcel发送给进程B,进程B接收到传入的Parcel后,调用Binder.onTransact()方法,并使用Parcel进行回复。在等待进程B回复的过程中,进程A是阻塞的。

绑定服务进行交互的几种方式

1.Extending the binder class

应用场景

Service 是Applicatin私有的,并且与Application运行在同进程中(比较普遍),因为该方式不支持进程间通讯。

创建Binder与Service:

public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();

public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}

@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
客户端调用:

public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}

/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}

/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;// 获取本地的IBinder对象句柄
mService = binder.getService();//通过IBinder句柄,获取Service的句柄
mBound = true;
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}


2.Use Messenger

应用场景:

使用消息驱动,支持IPC(Interface Progress Communication)。

===Handler异步消息处理线程详解===

示例代码:

public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;

/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}

/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());

/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}


客户端调用:

public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;

/** Flag indicating whether we have called bind on the service. */
boolean mBound;

/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service.  We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);//如果服务连接成功,则将服务端IBinder对象传递至客户端,mMessenger.getBinder();的值也是这里被初始化的;
mBound = true;//这样做的好处是,1)将IBinder的处理封装在Messenger类中,2)由IPC调用转为本地的异步线程处理
}

public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};

public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}


3.Use AIDL (Android Interface Define Language)

Android本身并不推荐使用AIDL,因为它需要支持多线程,使用它会使应用变得更复杂。

关于AIDL接口的定义:请查阅AIDL

操作步骤:

1.新建xxx.aidl文件,定义接口;

2.Android AIDL工具将自动编译在Gen目录下生成对应的Java文件(使用Eclipse开发环境)。

package com.example.android;
interface IServerServiceAidl{
void startServer(String command);
void stopServer();
}


实际上完全可以手动去实现这部分内容(如下面),

相较于使用AIDL在Gen目录下自动生成的JAVA文件来说,本质上并无区别;

public interface IServerServiceAidl extends IInterface {
/** Local-side IPC implementation stub class. */

public void startServer(String command) throws RemoteException;

public void stopServer() throws RemoteException;
}


public class Proxy implements IServerServiceAidl {
private IBinder mRemote;

Proxy(IBinder remote) {
mRemote = remote;
}

@Override
public IBinder asBinder() {
return mRemote;
}

public String getInterfaceDescriptor() {
return Stub.DESCRIPTOR;
}

@Override
public void startServer(String command) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(Stub.DESCRIPTOR);
_data.writeString(command);
mRemote.transact(Stub.TRANSACTION_STARTSERVER, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}

@Override
public void stopServer() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(Stub.DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_STOPSERVER, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}


public abstract class Stub extends Binder implements IServerServiceAidl {
public static final String DESCRIPTOR = "IServerServiceAidl";
public static final int TRANSACTION_STARTSERVER = (IBinder.FIRST_CALL_TRANSACTION + 0);
public static final int TRANSACTION_STOPSERVER = (IBinder.FIRST_CALL_TRANSACTION + 1);

/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}

/**
* Cast an IBinder object into an IServerServiceAidl interface, generating a
* proxy if needed.
*/
public static IServerServiceAidl asInterface(IBinder obj) {
if ((obj == null)) {
return null;
}
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

if (((iin != null) && (iin instanceof IServerServiceAidl))) {
Log.d("debug", "Return :Local Binder Object");
return ((IServerServiceAidl) iin);
}
Log.d("debug", "Return :Remote Binder Proxy Object");
return new Proxy(obj);
}

@Override
public IBinder asBinder() {
return this;
}

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_STARTSERVER: {
data.enforceInterface(DESCRIPTOR);
String _arg0;
_arg0 = data.readString();
this.startServer(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_STOPSERVER: {
data.enforceInterface(DESCRIPTOR);
this.stopServer();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

}
这里当使用到Binder时,将会先判断是否是本地的Binder,如果是本地的就直接使用了没有必要去远程ServiceManager去索取;

接下来就是通过Parcel交互数据的过程,这里需要校验下DESCRIPTOR,来判断请求者是否是真的想请求指定服务程序。

附上一些扩展阅读资料以帮助更好的理解Binder:

Android Binder RPC机制了解


Android Binder设计与实现 – 设计篇

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

点击下载 mDemo-Binder 机制学习资源
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: