[转帖]android进程之间使用AIDL进行通信_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3250 | 回复: 0   主题: [转帖]android进程之间使用AIDL进行通信        下一篇 
刘伟
注册用户
等级:少校
经验:938
发帖:82
精华:0
注册:2013-6-24
状态:离线
发送短消息息给刘伟 加好友    发送短消息息给刘伟 发消息
发表于: IP:您无权察看 2013-7-1 8:43:23 | [全部帖] [楼主帖] 楼主

     欢迎阅读本文,你能关注本文,你知道你需要进程间通信、需要AIDL(以及Binder),那么可以默认你对这些概念已经有了一些了解,你(大致)知道它们是什么,它们有什么用,所以为了节约大家的眼力和时间,在此我不复制粘贴网上泛滥的博客或者翻译冗长的android文档。

     关于AIDL的介绍在文档:docs/guide/developing/tools/aidl.html

     关于IBinder的介绍在文档:docs/reference/android/os/IBinder.html

     以及Binder:docs/reference/android/os/Binder.html

     在后文中,我将以我自己的理解向你介绍相关的概念。以我目前粗浅的经验,应用程序使用AIDL的地方,几乎都和Service有关,所以你也需要知道一些关于Service的知识。日后得闲我也会继续写一些关于Service的贴。

     本文将以一个例子来和你分享使用AIDL的基础技能,这个例子里有:

1、一个类mAIDLActivity,继承Activity。里面有三个按钮,text分别为StartService,StopService,CallbackTest。

2、一个类mAIDLService,继承Service。为了充分展示ADIL的功能,它做以下工作:当用户点击CallbackTest按钮时,从mAIDLActivity调用mAIDLService中的Stub 对象的一个方法invokCallBack(),而这个方法又会调用mAIDLActivity中Stub 对象的一个方法performAction(),这个方法在屏幕上显示一个toast。没什么意义,只是展示一下AIDL如何使用。

3、两个AIDL文件:forService.aidl和forActivity.aidl。对应名字,在Service和Activity中分别有对象需要用到它们定义的接口。

4、相关XML文件,略过。关于manifest中Service的语法,见docs/guide/topics/manifest/service-element.html。你也可以简单地在<application></application>中加入

<service android:name=".mAIDLService" android:process=":remote"> </service>


开发环境为Eclipse。

拣重要的先说,来看看aidl文件的内容:

文件:forActivity.aidl

package com.styleflying.AIDL;
interface forActivity {
      void performAction();
}


文件:forService.aidl

package com.styleflying.AIDL;
import com.styleflying.AIDL.forActivity;
interface forService {
      void registerTestCall(forActivity cb);
      void invokCallBack();
}


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

在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码贴上,不用细看。

文件forActivity.java:

/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D://workspace//AIDLTest//src//com//styleflying//AIDL//forActivity.aidl
*/
package com.styleflying.AIDL;
import java.lang.String;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Binder;
import android.os.Parcel;
public interface forActivity extends android.os.IInterface
{
      /** Local-side IPC implementation stub class. */
      public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forActivity
      {
            private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.forActivity";
            /** Construct the stub at attach it to the interface. */
            public Stub()
            {
                  this.attachInterface(this, DESCRIPTOR);
            }
            /**
            * Cast an IBinder object into an forActivity interface,
            * generating a proxy if needed.
            */
            public static com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)
            {
                  if ((obj==null)) {
                        return null;
                  }
                  android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
                  if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forActivity))) {
                        return ((com.styleflying.AIDL.forActivity)iin);
                  }
                  return new com.styleflying.AIDL.forActivity.Stub.Proxy(obj);
            }
            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_performAction:
                        {
                              data.enforceInterface(DESCRIPTOR);
                              this.performAction();
                              reply.writeNoException();
                              return true;
                        }
                  }
                  return super.onTransact(code, data, reply, flags);
            }
            private static class Proxy implements com.styleflying.AIDL.forActivity
            {
                  private android.os.IBinder mRemote;
                  Proxy(android.os.IBinder remote)
                  {
                        mRemote = remote;
                  }
                  public android.os.IBinder asBinder()
                  {
                        return mRemote;
                  }
                  public java.lang.String getInterfaceDescriptor()
                  {
                        return DESCRIPTOR;
                  }
                  public void performAction() throws android.os.RemoteException
                  {
                        android.os.Parcel _data = android.os.Parcel.obtain();
                        android.os.Parcel _reply = android.os.Parcel.obtain();
                        try {
                              _data.writeInterfaceToken(DESCRIPTOR);
                              mRemote.transact(Stub.TRANSACTION_performAction, _data, _reply, 0);
                              _reply.readException();
                        }
                        finally {
                              _reply.recycle();
                              _data.recycle();
                        }
                  }
            }
            static final int TRANSACTION_performAction = (IBinder.FIRST_CALL_TRANSACTION + 0);
      }
      public void performAction() throws android.os.RemoteException;
}


文件forService.java:

/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D://workspace//AIDLTest//src//com//styleflying//AIDL//forService.aidl
*/
package com.styleflying.AIDL;
import java.lang.String;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Binder;
import android.os.Parcel;
public interface forService extends android.os.IInterface
{
      /** Local-side IPC implementation stub class. */
      public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forService
      {
            private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.forService";
            /** Construct the stub at attach it to the interface. */
            public Stub()
            {
                  this.attachInterface(this, DESCRIPTOR);
            }
            /**
            * Cast an IBinder object into an forService interface,
            * generating a proxy if needed.
            */
            public static com.styleflying.AIDL.forService asInterface(android.os.IBinder obj)
            {
                  if ((obj==null)) {
                        return null;
                  }
                  android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
                  if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forService))) {
                        return ((com.styleflying.AIDL.forService)iin);
                  }
                  return new com.styleflying.AIDL.forService.Stub.Proxy(obj);
            }
            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_registerTestCall:
                        {
                              data.enforceInterface(DESCRIPTOR);
                              com.styleflying.AIDL.forActivity _arg0;
                              _arg0 = com.styleflying.AIDL.forActivity.Stub.asInterface(data.readStrongBinder());
                              this.registerTestCall(_arg0);
                              reply.writeNoException();
                              return true;
                        }
                        case TRANSACTION_invokCallBack:
                        {
                              data.enforceInterface(DESCRIPTOR);
                              this.invokCallBack();
                              reply.writeNoException();
                              return true;
                        }
                  }
                  return super.onTransact(code, data, reply, flags);
            }
            private static class Proxy implements com.styleflying.AIDL.forService
            {
                  private android.os.IBinder mRemote;
                  Proxy(android.os.IBinder remote)
                  {
                        mRemote = remote;
                  }
                  public android.os.IBinder asBinder()
                  {
                        return mRemote;
                  }
                  public java.lang.String getInterfaceDescriptor()
                  {
                        return DESCRIPTOR;
                  }
                  public void registerTestCall(com.styleflying.AIDL.forActivity cb) 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.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
                              mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);
                              _reply.readException();
                        }
                        finally {
                              _reply.recycle();
                              _data.recycle();
                        }
                  }
                  public void invokCallBack() throws android.os.RemoteException
                  {
                        android.os.Parcel _data = android.os.Parcel.obtain();
                        android.os.Parcel _reply = android.os.Parcel.obtain();
                        try {
                              _data.writeInterfaceToken(DESCRIPTOR);
                              mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);
                              _reply.readException();
                        }
                        finally {
                              _reply.recycle();
                              _data.recycle();
                        }
                  }
            }
            static final int TRANSACTION_registerTestCall = (IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_invokCallBack = (IBinder.FIRST_CALL_TRANSACTION + 1);
      }
      public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException;
      public void invokCallBack() throws android.os.RemoteException;
}


两段代码差不多,前面基本一样,从后面看,最后跟着我们在AIDL中自定义的方法,没有实现。两个文件各定义一个了接口,这两个接口分别会在Activity和Service中使用,在那里我们将实现自定义的方法。两个接口中都定义了一个抽象类Stub,实现所在的接口。Stub中又有一个类Proxy。Stub中有一个static的asInterface()方法,里面有很多return语句,在mAIDLActivity中调用它时,它返回一个新创建的内部类Proxy对象。

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

再看mAIDLActivity.java:

package com.styleflying.AIDL;
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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class mAIDLActivity extends Activity {
      private static final String TAG = "AIDLActivity";
      private Button btnOk;
      private Button btnCancel;
      private Button btnCallBack;
      private void Log(String str) {
            Log.d(TAG, "------ " + str + "------");
      }
      private forActivity mCallback = new forActivity.Stub() {
            public void performAction() throws RemoteException
            {
                  Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();
            }
      };
      forService mService;
      private ServiceConnection mConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className,
            IBinder service) {
                  mService = forService.Stub.asInterface(service);
                  try {
                  mService.registerTestCall(mCallback);}
                  catch (RemoteException e) {
                  }
            }
            public void onServiceDisconnected(ComponentName className) {
                  Log("disconnect service");
                  mService = null;
            }
      };
      @Override
      public void onCreate(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(new OnClickListener() {
                  public void onClick(View v) {
                        Bundle args = new Bundle();
                        Intent intent = new Intent(mAIDLActivity.this, mAIDLService.class);
                        intent.putExtras(args);
                        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                        startService(intent);
                  }
            });
            btnCancel.setOnClickListener(new OnClickListener() {
                  public void onClick(View v) {
                        unbindService(mConnection);
                        //stopService(intent);
                  }
            });
            btnCallBack.setOnClickListener(new OnClickListener() {
                  @Override
                  public void onClick(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:

package com.styleflying.AIDL;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
public class mAIDLService extends Service {
      private static final String TAG = "AIDLService";
      private forActivity callback;
      private void Log(String str) {
            Log.d(TAG, "------ " + str + "------");
      }
      @Override
      public void onCreate() {
            Log("service create");
      }
      @Override
      public void onStart(Intent intent, int startId) {
            Log("service start id=" + startId);
      }
      @Override
      public IBinder onBind(Intent t) {
            Log("service on bind");
            return mBinder;
      }
      @Override
      public void onDestroy() {
            Log("service on destroy");
            super.onDestroy();
      }
      @Override
      public boolean onUnbind(Intent intent) {
            Log("service on unbind");
            return super.onUnbind(intent);
      }
      public void onRebind(Intent intent) {
            Log("service on rebind");
            super.onRebind(intent);
      }
      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;
            }
      };
}


注意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)。

欢迎���读、收藏本文。例子随手写的,功能只在演示AIDL的使用。您可以转载本文,但请勿盲目乱贴。不是我小气,我不权威,我怕它被贴到泛滥,以讹传讹,害了人。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论