Android跨进程调用接口,Android中使用AIDL时的跨进程回调—Server回调Client

这两个文件和Java文件放置的地方一样,看包名。

在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。两个文件各定义一个了接口,这两个接口分别会在Activity和Service中使用,在那里我们将实现自定义的方法。两个接口中都定义了一个抽象类Stub,实现所在的接口。Stub中又有一个类Proxy。Stub中有一个static的asInterface()方法,里面有很多return语句,在mAIDLActivity中调用它时,它返回一个新创建的内部类Proxy对象。

这个Stub对我们来说很有用,它继承了Binder。Binder有什么用呢?一个类,继承了Binder,那么它的对象就可以被远程的进程使用了(前提是远程进程获取了这个类的对象【对象的引用】,至于如如何获得看下文),在本例中就是说,如果一个Service中有一个继承了Stub的类的对象,那么这个对象中的方法就可以在Activity中使用,对Activity也是这样。至于Binder的细节,网上有很多贴介绍,看不明白也不影响我们完成这个例子。

再看mAIDLActivity.java:

packagecom.styleflying.AIDL;

importandroid.app.Activity;

importandroid.content.ComponentName;

importandroid.content.Context;

importandroid.content.Intent;

importandroid.content.ServiceConnection;

importandroid.os.Bundle;

importandroid.os.IBinder;

importandroid.os.RemoteException;

importandroid.util.Log;

importandroid.view.View;

importandroid.view.View.OnClickListener;

importandroid.widget.Button;

importandroid.widget.Toast;

publicclassmAIDLActivityextendsActivity {

privatestaticfinalString TAG ="AIDLActivity";

privateButton btnOk;

privateButton btnCancel;

privateButton btnCallBack;

privatevoidLog(String str) {

Log.d(TAG, "------ "+ str +"------");

}

privateforActivity mCallback =newforActivity.Stub() {

publicvoidperformAction()throwsRemoteException

{

Toast.makeText(mAIDLActivity.this,"this toast is called from service",1).show();

}

};

forService mService;

privateServiceConnection mConnection =newServiceConnection() {

publicvoidonServiceConnected(ComponentName className,

IBinder service) {

mService = forService.Stub.asInterface(service);

try{

mService.registerTestCall(mCallback);}

catch(RemoteException e) {

}

}

publicvoidonServiceDisconnected(ComponentName className) {

Log("disconnect service");

mService = null;

}

};

@Override

publicvoidonCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

btnOk = (Button)findViewById(R.id.btn_ok);

btnCancel = (Button)findViewById(R.id.btn_cancel);

btnCallBack = (Button)findViewById(R.id.btn_callback);

btnOk.setOnClickListener(newOnClickListener() {

publicvoidonClick(View v) {

Bundle args = newBundle();

Intent intent = newIntent(mAIDLActivity.this, mAIDLService.class);

intent.putExtras(args);

bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

startService(intent);

}

});

btnCancel.setOnClickListener(newOnClickListener() {

publicvoidonClick(View v) {

unbindService(mConnection);

//stopService(intent);

}

});

btnCallBack.setOnClickListener(newOnClickListener() {

@Override

publicvoidonClick(View v)

{

try

{

mService.invokCallBack();

} catch(RemoteException e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

});

}

}

很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService =

forService.Stub.asInterface(service);给mService赋值了,这个mService是一个forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接Service的时候被系统调用,这个service参数的值来自哪里呢?看mAIDLService.java:

packagecom.styleflying.AIDL;

importandroid.app.Service;

importandroid.content.Intent;

importandroid.os.IBinder;

importandroid.os.RemoteCallbackList;

importandroid.os.RemoteException;

importandroid.util.Log;

publicclassmAIDLServiceextendsService {

privatestaticfinalString TAG ="AIDLService";

privateforActivity callback;

privatevoidLog(String str) {

Log.d(TAG, "------ "+ str +"------");

}

@Override

publicvoidonCreate() {

Log("service create");

}

@Override

publicvoidonStart(Intent intent,intstartId) {

Log("service start id="+ startId);

}

@Override

publicIBinder onBind(Intent t) {

Log("service on bind");

returnmBinder;

}

@Override

publicvoidonDestroy() {

Log("service on destroy");

super.onDestroy();

}

@Override

publicbooleanonUnbind(Intent intent) {

Log("service on unbind");

returnsuper.onUnbind(intent);

}

publicvoidonRebind(Intent intent) {

Log("service on rebind");

super.onRebind(intent);

}

privatefinalforService.Stub mBinder =newforService.Stub() {

@Override

publicvoidinvokCallBack()throwsRemoteException

{

callback.performAction();

}

@Override

publicvoidregisterTestCall(forActivity cb)throwsRemoteException

{

callback = cb;

}

};

}

注意onBind(),它的返回类型为IBinder,返回了一个mBinder,看看mBinder的定义:

private

final forService.Stub mBinder = new forService.Stub() {

@Override

public void

invokCallBack() throws RemoteException

{

callback.performAction();

}

@Override

public void

registerTestCall(forActivity cb) throws RemoteException

{

callback =

cb;

}

};

它是实现了我们在AIDL中定义的方法,这个mBinder最终返回给了mAIDLActivity中的mService,于是在mAIDLActivity中可以使用mBinder中的方法了。在mAIDLActivity中也有一个类似mBinder的对象,看看定义:

private forActivity mCallback = new forActivity.Stub()

{

public void performAction() throws

RemoteException

{

Toast.makeText(mAIDLActivity.this, "this toast is

called from service", 1).show();

}

};

我们要在界面上显示一个toast,就是在这里实现的。这个对象,在mConnection的onServiceConnected()被调用时,通过调用mService(也就是远程的mAIDLService中的mBinder)的registerTestCall(),传递给了mAIDLService,于是在mAIDLService中可以调用performAction()了。

做一个大致总结,我们使用AIDL是要做什么呢:

让Acticity(或者说一个进程/一个类?)和Service(或者说远端进程/远端类/对象?)获取对方的一个Stub对象,这个对象在定义时实现了我们在AIDL中定义的方法,于是这些远程对象中的方法可以在本地使用了。如果这种使用(通信)是单向的,比如只是Activity需要通知Service做什么,那么只要Service中有一个Stub对象,并且传给Acticity就够了。

至于如何获得远程的Stub,参看上面的代码,看mConnection、registerTestCall、onRebind,它们展示了一种方法。

另外,有时候我们可能在一个类中有多个Stub对象,它们都要给远程交互的类的实例,这个时候可以考虑使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。

实现接口时有几个原则:.抛出的异常不要返回给调用者.

跨进程抛异常处理是不可取的..IPC调用是同步的。如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。

也就是IPC调用会挂起应用程序导致界面失去响应. 这种情况应该考虑单起一个线程来处理..不能在AIDL接口中声明静态属性。IPC的调用步骤:1.

声明一个接口类型的变量,该接口类型在.aidl文件中定义。2.

实现ServiceConnection。3.

调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递.4.

在ServiceConnection.onServiceConnected()实现中,你会接收一个IBinder实例(被调用的Service).

调用

YourInterfaceName.Stub.asInterface((IBinder)service)将参数转换为YourInterface类型。5.

调用接口中定义的方法。

你总要检测到DeadObjectException异常,该异常在连接断开时被抛出。它只会被远程方法抛出。6.

断开连接,调用接口实例中的ApplicationContext.unbindService()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值