最近参与了一个项目,其中有用到两个APK间进行通信,最终采用的是AIDL,于是自己小研究了下,如有错误,请大家指正。
1. 创建.aidl文件
首先,创建.aidl文件。这个文件类似于声明文件,对于服务器端而言,就是声明你需要对外提供什么接口;对于客户端来说,声明了自己将要用到的接口。所以,不仅服务器端要创建.aidl文件,客户端同样需要。而且是客户端的.aidl文件要和服务器端的一样。所以服务器端一旦公布了对外接口,最好就不要改啦,因为会有很多客户端将用。
下面这两个文件IEmilyService.aidl 是EmilyService.apk 里的定义的,IEmilyServiceCallBack.aidl 这个是EmilySecondClient.apk定义的,因为这个两个apk需要进行双向通信。
但是在两个apk中,这个两个文件是必须都具备的。说白了就是为了方便互相调接口...
IEmilyService.aidl
- package com.example.fwk;
- import com.example.fwk.IEmilyServiceCallBack;
- interface IEmilyService {
- void registerCallback(IEmilyServiceCallBack cb);
- void unregisterCallback(IEmilyServiceCallBack cb);
- void serviceShow();
- }
IEmilyServiceCallBack.aidl
- package com.example.fwk;
- interface IEmilyServiceCallBack {
- void serviceCallBackShow();
- }
2. 实现接口并将接口暴露给客户端
这个两个文件在编译后会自动生成.java文件。额,因为我用的是eclipse, 一运行就自己生成了,也没仔细看里面具体都有啥。从文档里得知,里面东西还是很重要的。尤其是一个内部类Stub,它是父类接口的抽象实现,里面定义了.aidl中的所有方法。
mBinder是IEmilyService.Stub的对象,里面实现了IEmilyService.aidl里定义的所有方法。当有客户端连接的时候,也就是来onBind(), 客户端会得到mBinder这个实例。
EmilyService
- package com.example.emilyservice;
- import com.example.fwk.IEmilyService;
- import com.example.fwk.IEmilyServiceCallBack;
- import android.os.IBinder;
- import android.os.RemoteCallbackList;
- import android.os.RemoteException;
- import android.app.Service;
- import android.content.Intent;
- import android.util.Log;
- public class EmilyService extends Service {
- private static final String TAG = "EmilyService";
- /*
- * This is a list of callbacks that have been registered with the
- * service.
- */
- final RemoteCallbackList<IEmilyServiceCallBack> mCallbacks =
- new RemoteCallbackList<IEmilyServiceCallBack>();
- /*
- * Implements the interface.
- * 1. The mBinder is an instance of the Stub class (a Binder), which defines the RPC interface for the service.
- * 2. This instance will be exposed to clients, so the clients can interact with the service.
- * 3. If one service takes too much time to complete a request, you should avoid to call it from the main thread,
- * you should call it from a separate thread in the client, in this way to avoid ANR.
- */
- private final IEmilyService.Stub mBinder = new IEmilyService.Stub() {
- public void registerCallback(IEmilyServiceCallBack cb) {
- Log.i(TAG, "___________registerCallback()");
- if (cb != null) mCallbacks.register(cb);
- }
- public void unregisterCallback(IEmilyServiceCallBack cb) {
- Log.i(TAG, "___________unregisterCallback()");
- if (cb != null) mCallbacks.unregister(cb);
- }
- public void serviceShow() throws RemoteException {
- Log.i(TAG, "___________serviceShow()");
- testClients(null);
- }
- };
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- return mBinder;
- }
- /*
- * Test the clients.
- */
- public void testClients(IEmilyServiceCallBack cb) {
- if (cb != null) {
- Log.i(TAG, "cb != null");
- try {
- cb.serviceCallBackShow();
- } catch (RemoteException e) {
- }
- } else {
- // Broadcast to all clients the new value.
- final int count = mCallbacks.beginBroadcast();
- for (int i=0; i < count; i++) {
- try {
- Log.i(TAG, "onServiceShowFinished____i = " + i);
- mCallbacks.getBroadcastItem(i).serviceCallBackShow();
- } catch (RemoteException e) {
- }
- }
- mCallbacks.finishBroadcast();
- }
- }
- }
3. 当一个客户端调bindservice()去连接service的时候,客户端调用onServiceConected()回调方法。
Client
- package com.example.emilysecondclient;
- import com.example.fwk.IEmilyService;
- import com.example.fwk.IEmilyServiceCallBack;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.util.Log;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- public class MainActivity extends Activity {
- private static String TAG = "EmilySecondClient";
- private static String ACTION_START_EMILY_SERVICE = "android.intent.action.EMILY_SERVICE";
- private IEmilyService mEmilyService = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // When the client call the bindService() to connect to Emily service,
- // the client's onServiceConnected() callback receives IBinder that the
- // client can use to communicate with the service.
- Intent serviceIntent = new Intent(ACTION_START_EMILY_SERVICE);
- bindService(serviceIntent, mEmilyServiceConnection, Context.BIND_AUTO_CREATE);
- Button button1 = (Button)findViewById(R.id.button1);
- button1.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- serviceShowInClient();
- }
- });
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.activity_main, menu);
- return true;
- }
- private final ServiceConnection mEmilyServiceConnection = new ServiceConnection() {
- // Called when the connection with the service is established.
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.i(TAG, "call service connected");
- mEmilyService = IEmilyService.Stub.asInterface(service);
- // We want to monitor the service for as long as we are
- // connected to it.
- try {
- mEmilyService.registerCallback(mCallBack);
- } catch (RemoteException e) {
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- Log.i(TAG, "call service disconnected");
- mEmilyService = null;
- }
- };
- private final IEmilyServiceCallBack.Stub mCallBack = new IEmilyServiceCallBack.Stub() {
- public void serviceCallBackShow() throws RemoteException {
- Log.i(TAG, "___________serviceCallBackShow()");
- }
- };
- private void serviceShowInClient() {
- try {
- mEmilyService.serviceShow();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
以上只贴出来了一个Client的代码,另外一个client代码是类似的。
下面是运行出的log.
The log
- I/EmilyFirstClient( 4163): call service connected
- I/EmilyService( 4084): Binder API: registerCallback()
- I/EmilyService( 4084): ___________serviceShow()
- I/EmilySecondClient( 4206): call service connected
- I/EmilyService( 4084): Binder API: registerCallback()
- I/EmilyService( 4084): ___________serviceShow()
- I/EmilyFirstClient( 6830): call service connected
- I/EmilyService( 6711): ___________registerCallback()
- I/EmilyService( 6711): ___________serviceShow()
- I/EmilyService( 6711): onServiceShowFinished____i = 0
- I/EmilyFirstClient( 6830): ___________serviceCallBackShow()
- I/EmilySecondClient( 6931): call service connected
- I/EmilyService( 6711): ___________registerCallback()
- I/EmilyService( 6711): ___________serviceShow()
- I/EmilyService( 6711): onServiceShowFinished____i = 0
- I/EmilySecondClient( 6931): ___________serviceCallBackShow()
还是要好好研究下:
http://developer.android.com/guide/components/aidl.html