技术改变世界 阅读塑造人生! - shaogx.com

This string was altered by TechBlog\Plugins\Example.; This is an example to show the potential of an offcanvas layout pattern in Bootstrap. Try some responsive-range viewport sizes to see it in action.

Android中AIDL的简单使用

AIDL这里就不加累述它的概念定义等等,免得长篇大幅。下面介绍的是简单的一次使用AIDL成功与service通信的一个例子:1.在项目包下新建一个IInfo.aidl,并在其中添加你要调用的方法,格式和java中接口一样。package com.android.server; ... 全文

AIDL的简单使用 Android中AIDL

Android使用AIDL实现进程间通信

Android的每个应用程序都是一个不同的进程,在Android平台一个进程通常不能访问另一个进程的内存空间。 比如一个应用程序有两个进程,一个进程负责UI的展示,而另一个进程(通常是在此进程中使用一个service)用来进行网络资源的请求,需要主进程和服务进程之间进行数据的传递。(微信就是使用的这种机制) Android提供了AIDL来实现进程间通信(IPC),AIDL全称为Android Interface Definition Language。AIDL IPC机制是面向接口的,使用代理类在客户端和服务端之间进行数据传递。那么如何使用AIDL实现进程间通信呢?... 全文

AIDL进程间通信 Android使用AIDL

Android进程间通信

一、概念及说明Android为了屏蔽进程的概念,利用不同的组件[Activity、Service]来表示进程之间的通信!组件间通信的核心机制是Intent,通过Intent可以开启一个Activity或Service,不论这个Activity或Service是属于当前应用还是其它应用的!                                                                                本文如有bug,请指出啊!!大家一同进步!!                                                             谢谢!!Intent包含两部分:1、目的[action]--要往哪里去2、内容[category、data]--路上带了些啥,区分性数据或内容性数据Intent类型:1、显式--直接指定消息目的地,只适合同一进程内的不同组件之间通信new Intent(this,Target.class)2、隐式--AndroidMainifest.xml中注册,一般用于跨进程通信new Intent(String action) 二、实现-Intent简单进程间通信显式的Intent较为简单! 如何实现隐式Intent呢?在AndroidManifest.xml文件中定义<activity>说明:1、一个<activity>包括:零个或多个<intent-filter>它主要是作为匹配的标准,能否匹配成功由<action>、<category>、<data>三个tag共同决定的。 2、一个<intent-filter>包括:一个或多个 <action>零个或多个 <category>  指定<activity>的分类特征eg:<category android:name="android.intent.category.LAUNCHER" /> --说明该<activity>是该project运行的第一个界面<category android:name="android.intent.category.HOME" /> --说明该<activity>可以作为Launcher的,即系统操作界面<category android:name="android.intent.category.DEFAULT" /> --缺省情况零个或一个 <data>-- 指定携带的数据的类型,使用MIME类型描述方式来描述eg:<data android:mimeType="video/mpeg" />video/mpeg表示编码格式为mpeg的视频,也可以使用通配符video/*表示任意格式的视频文件类型; 在查询ContentProvider时,可以使用<data android:mimeType="vnd.android.cursor.dir/vnd.myq.note" />查询上来的数据是多个记录<data android:mimeType="vnd.android.cursor.item/vnd.myq.note" />查询上来的数据是单个记录如上设置,要重写SQLiteOpenHelper的getType(Uri uri)方法eg: @Override public String getType(Uri uri) {  final int match = sUriMatcher.match(uri) ;  switch(match)  {  case NOTES :  case LIVE_FOLDER_NOTES:   return "vnd.android.cursor.dir/vnd.myq.note" ;     case NOTES_ID :   return "vnd.android.cursor.item/vnd.myq.note" ;     default:   throw new IllegalArgumentException("invalid uri : " + uri) ;  } } 数据的URI由scheme(协议),host,port,path四部分:scheme://host:port/path<data android:scheme="http://localhost:8080/test.jsp" />3、一个Intent对应多种匹配结果的处理说明 一个intent有多个可匹配的处理组件,系统如何处理?分响应消息的组件类型:1)如果是service那么这些service都可以启动并处理消息。2)如果是Activity则会弹出一个对话框让用户进行选择。 4、安全性问题 如果不同进程间的组件可以通过隐式消息互相通信,那程序不是可以轻易调用到其他的程序或者系统中的一些敏感程序的组件,这样会不会很不安全呢?其实Android在安全方面有一个统一,完备和轻便的安全策略模型。简单一点说就是:权限设置问题我们可以自己定义permission,然后在需要的组件处设置该permission,那么用户要想该组件,必须要配置该permission,否则访问失败的!eg:1、定义permission<permission-group android:name="android.permission-group.MYQ_INFO"/> <permission     android:name="com.myq.android.permission.DATETIME_SERVICE"     android:permissi     android:protecti     /> 2、配置permission<service android:name=".DateTimeService" android:permission="com.myq.android.permission.DATETIME_SERVICE">   <intent-filter> <action android:name="com.myq.android.MultiProcessTest.DATETIMESERVICE_ACTION" />   </intent-filter></service> 3、使用permission<uses-permission android:name="com.myq.android.permission.DATETIME_SERVICE"/> 三、IPC机制有了Intent这种基于消息的进程内或进程间通信模型,我们就可以通过Intent去开启一个Service,可以通过Intent跳转到另一个Activity,不论上面的Service或Activity是在当前进程还是其它进程内即不论是当前应用还是其它应用的Service或Activity,通过消息机制都可以进行通信!但是通过消息机制实现的进程间通信,有一个弊端就是,如果我们的Activity与Service之间的交往不是简单的Activity开启Service操作,而是要随时发一些控制请求,那么必须就要保证Activity在Service的运行过程中随时可以连接到Service。eg:音乐播放程序后台的播放服务往往独立运行,以方便在使用其他程序界面时也能听到音乐。同时这个后台播放服务也会定义一个控制接口,比如播放,暂停,快进等方法,任何时候播放程序的界面都可以连接到播放服务,然后通过这组控制接口方法对其控制。 如上的需求仅仅通过Intent去开启Service就无法满足了!从而Android的显得稍微笨重的IPC机制就出现了,然而它的出现只适用于Activity与Service之间的通信,类似于远程方法调用,就像是C/S模式的访问,通过定义AIDL接口文件来定义一个IPC接口,Server端实现IPC接口,Client端调用IPC接口的本地代理。由于IPC调用是同步的,如果一个IPC服务需要超过几毫秒的时间才能完成的话,你应该避免在Activity的主线程中调用,否则IPC调用会挂起应用程序导致界面失去响应。在 这种情况下,应该考虑单起一个线程来处理IPC访问。两个进程间IPC看起来就象是一个进程进入另一个进程执行代码然后带着执行的结果返回。IPC机制鼓励我们“尽量利用已有功能,利用IPC和包含已有功能的程序协作完成一个完整的项目” IPC实现demo:我的project -- MultiProcessTestpackage -- com.myq.android.MultiProcessTest 1、AIDL文件,我是放在package下,文件名称为:IDateTimeService.aidl文件内容为:package com.myq.android.MultiProcessTest ;interface IDateTimeService { String getCurrentDateTime(in String format) ;} 如果正确配置,会在gen下,生成同名的java文件简单摘要://我们需要实现的类Stubpublic interface IDateTimeService extends android.os.IInterface{...public static abstract class Stubextends android.os.Binder implements com.myq.android.MultiProcessTest.IDateTimeService{ ...//获取实例的方法asInterfacepublic static com.myq.android.MultiProcessTest.IDateTimeService asInterface(android.os.IBinder obj){  ...} ...}//我们自己的业务方法,需要实现的public java.lang.String getCurrentDateTime(java.lang.String format) throws android.os.RemoteException;} 2、Service中实现IDateTimeService.Stubeg:package com.myq.android.MultiProcessTest;import java.text.SimpleDateFormat;import java.util.Date;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log; public class DateTimeService extends Service {  public static final String DATETIME_SERVICE_ACTION = "com.myq.android.MultiProcessTest.DATETIMESERVICE_ACTION" ;  private static final String TAG = "--------DateTimeService-------" ;  private  SimpleDateFormat sdf ;  private final IDateTimeService.Stub stub = new IDateTimeService.Stub() {    public String getCurrentDateTime(String format) throws RemoteException {   return getCurrentDateTimeString(format) ;  } } ;  private synchronized String getCurrentDateTimeString(String format) {     sdf = new SimpleDateFormat(format) ;     final String temp = sdf.format(new Date()) ;   Log.i(TAG,"getCurrentDateTimeString--" + Thread.currentThread() + "--" + temp) ;   return temp ; }  public IBinder onBind(Intent arg0)  {  Log.i(TAG, "onBind--" + Thread.currentThread()) ;  return stub; }}3、Client端代码实现private ServiceConnection mServiceConn = new ServiceConnection() {    public void onServiceConnected(ComponentName name, IBinder service) {   mDateTimeService = IDateTimeService.Stub.asInterface(service) ;  }    public void onServiceDisconnected(ComponentName name) {   mDateTimeService = null ;  } } ; 说明:网上的好多资料都没有涉及IPC调用的AIDL的具体说明!它本质上是Server端和Client端都具有相同的AIDL文件,要位于相同的包下,即package的包名药一样,然后才能正确的通过proxy访问,否则client与server的aidl文件处于不同package会出错的。 aidl模型如下:                |<--------------------aidl---------------------->| client端-->proxy  ----------parcel数据包-------- stub<---server端从而proxy+parcel+stub构成了aidl.只不过,proxy运行在客户进程,而stub运行在服务端进程。当你通过aidl去访问服务端时,客户端会阻塞在proxy,服务端处理完后,通知proxy返回。 四、附件及说明1、附件是我测试所用的demo,我用的系统是ubuntu9,Android2.2版本基本功能:可以根据用户选择的不同输出格式输出当前系统的时间。2、运行顺序:先运行Server端:MultiProcessTest再运行Client端:MultiProcessTestClient 3、注意点:Server和Client端的AIDL文件必须要位于同package下,否则会出错安全性问题实现,权限控制--定义、配置、使用异步处理问题--Handler  本文出自 “苗运齐的博客” 博客,请务必保留此出处http://myqdroid.blog.51cto.com/2057579/394189... 全文

Android进程间通信 Android AIDL实现 Android IPC机制 Android AIDL Android IPC

Android AIDL使用详解

1.什么是aidl:aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口 icp:interprocess communication :内部进程通信 2.既然aidl可以定义并实现进程通信,那么我们怎么使用它呢?文档/android-sdk/docs/guide/developing/tools/aidl.html中对步骤作了详细描述:... 全文

AIDL Android 通信

Android 使用【AIDL】调用外部服务

在Android 中有一种服务说是服务其实倒不如说是一个接口,这个接口名为:Android Interface Definition Language ,这个接口可提供跨进程访问服务,英文缩写为:AIDL。  此种服务的好处在于,多个应用程序之间建立共同的服务机制,通过AIDL在不同应用程序之间达到数据的共享和数据相互操作,下面将通过一个DEMO 演示AIDL 是如何为应用程序之间提供服务的。本文大纲为:... 全文

休闲 服务 移动开发 Android AIDL

Android Service学习之AIDL, Parcelable和远程服务

AIDL的作用    由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。    通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作。     AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。    AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。  选择AIDL的使用场合    官方文档特别提醒我们何时使用AIDL是必要的:只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service,以及想在你的service处理多线程。     如果不需要进行不同应用程序间的并发通信(IPC),you should create your interface by implementing a Binder;或者你想进行IPC,但不需要处理多线程的,则implement your interface using a Messenger。无论如何,在使用AIDL前,必须要理解如何绑定service——bindService。     在设计AIDL接口前,要提醒的是,调用AIDL接口是直接的方法调用的,不是我们所想象的调用是发生在线程里。而调用(call)来自local进程或者remote进程,有什么区别呢?尤其是以下情况(引用原文,不作翻译了,以免翻译有误):Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface by implementing a Binder). Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe. The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous. 定义AIDL接口    AIDL接口文件,和普通的接口内容没有什么特别,只是它的扩展名为.aidl。保存在src目录下。如果其他应用程序需要IPC,则那些应用程序的src也要带有这个文件。Android SDK tools就会在gen目录自动生成一个IBinder接口文件。service必须适当地实现这个IBinder接口。那么客户端程序就能绑定这个service并在IPC时从IBinder调用方法。    每个aidl文件只能定义一个接口,而且只能是接口的声明和方法的声明。 1.创建.aidl文件     AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。    其中对于Java编程语言的基本数据类型 (int, long, char, boolean等),String和CharSequence,集合接口类型List和Map,不需要import 语句。    而如果需要在AIDL中使用其他AIDL接口类型,需要import,即使是在相同包结构下。AIDL允许传递实现Parcelable接口的类,需要import.    需要特别注意的是,对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。     AIDL只支持接口方法,不能公开static变量。 例如 (IMyService.aidl):  package com.demo; import com.demo.Person; interface IMyService {         void savePersonInfo(in Person person);         List<Person> getAllPerson(); }2.实现接口    创建一个类实现刚才那个aidl的接口: public class RemoteService extends Service {         private LinkedList<Person> personList = new LinkedList<Person>();                  @Override         public IBinder onBind(Intent intent) {                 return mBinder;         }         private final IMyService.Stub mBinder = new IMyService.Stub(){                 @Override                 public void savePersonInfo(Person person) throws RemoteException {                         if (person != null){                                 personList.add(person);                         }                 }                 @Override                 public List<Person> getAllPerson() throws RemoteException {                         return personList;                 }         }; }     这里会看到有一个名为IMyService.Stub类,查看aidl文件生成的Java文件源代码就能发现有这么一段代码: /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.demo.IMyService    原来Stub类就是继承于Binder类,也就是说RemoteService类和普通的Service类没什么不同,只是所返回的IBinder对象比较特别,是一个实现了AIDL接口的Binder。     接下来就是关于所传递的数据Bean——Person类,是一个序列化的类,这里使用Parcelable 接口来序列化,是Android提供的一个比Serializable 效率更高的序列化类。    Parcelable需要实现三个函数:    1) void writeToParcel(Parcel dest, int flags) 将需要序列化存储的数据写入外部提供的Parcel对象dest。而看了网上的代码例子,个人猜测,读取Parcel数据的次序要和这里的write次序一致,否则可能会读错数据。具体情况我没试验过!    2) describeContents() 没搞懂有什么用,反正直接返回0也可以    3) static final Parcelable.Creator对象CREATOR  这个CREATOR命名是固定的,而它对应的接口有两个方法:    createFromParcel(Parcel source) 实现从source创建出JavaBean实例的功能    newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话(return new T[size])即可。估计本方法是供外部类反序列化本类数组使用。  仔细观察Person类的代码和上面所说的内容: public class Person implements Parcelable {         private String name;         private String telNumber;         private int age;         public Person() {}         public Person(Parcel pl){                 name = pl.readString();                 telNumber = pl.readString();                 age = pl.readInt();         }         public String getName() {                 return name;         }         public void setName(String name) {                 this.name = name;         }         public String getTelNumber() {                 return telNumber;         }         public void setTelNumber(String telNumber) {                 this.telNumber = telNumber;         }         public int getAge() {                 return age;         }         public void setAge(int age) {                 this.age = age;         }         @Override         public int describeContents() {                 return 0;         }         @Override         public void writeToParcel(Parcel dest, int flags) {                 dest.writeString(name);                 dest.writeString(telNumber);                 dest.writeInt(age);         }         public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {                 @Override                 public Person createFromParcel(Parcel source) {                         return new Person(source);                 }                 @Override                 public Person[] newArray(int size) {                         return new Person[size];                 }         }; }然后创建Person.aidl文件,注意这里的parcelable和原来实现的Parcelable 接口,开头的字母p一个小写一个大写: package com.demo; parcelable Person;      对于实现AIDL接口,官方还提醒我们:    1. 调用者是不能保证在主线程执行的,所以从一调用的开始就需要考虑多线程处理,以及确保线程安全;    2. IPC调用是同步的。如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。也就是IPC调用会挂起应用程序导致界面失去响应,这种情况应该考虑单独开启一个线程来处理。    3. 抛出的异常是不能返回给调用者(跨进程抛异常处理是不可取的)。 3. 客户端获取接口    客户端如何获取AIDL接口呢?通过IMyService.Stub.asInterface(service)来得到IMyService对象: private IMyService mRemoteService; private ServiceConnection mRemoteConnection = new ServiceConnection() {            public void onServiceConnected(ComponentName className, IBinder service) {                    mRemoteService = IMyService.Stub.asInterface(service);            }            public void onServiceDisconnected(ComponentName className) {                    mRemoteService = null;            }    }; 在生成的IMyService.java里面会找到这样的代码: /** * Cast an IBinder object into an com.demo.IMyService interface, * generating a proxy if needed. */ public static com.demo.IMyService asInterface(android.os.IBinder obj) {...} 而service的绑定没有什么不同: if (mIsRemoteBound) {         unbindService(mRemoteConnection); }else{         bindService(new Intent("com.demo.IMyService"),                                mRemoteConnection, Context.BIND_AUTO_CREATE); } mIsRemoteBound = !mIsRemoteBound; 通过IPC调用/传递数据    客户端绑定service后就能通过IPC来调用/传递数据了,直接调用service对象的接口方法:addPersonButton.setOnClickListener(                 new View.OnClickListener(){                         private int index = 0;                         @Override                         public void onClick(View view) {                                 Person person = new Person();                                 index = index + 1;                                 person.setName("Person" + index);                                 person.setAge(20);                                 person.setTelNumber("123456");                                 try {                                         mRemoteService.savePersonInfo(person);                                 } catch (RemoteException e) {                                         e.printStackTrace();                                 }                         }                 }); listPersonButton.setOnClickListener(                 new View.OnClickListener(){                         @Override                         public void onClick(View view) {                                 List<Person> list = null;                                 try {                                         list = mRemoteService.getAllPerson();                                 } catch (RemoteException e) {                                         e.printStackTrace();                                 }                                 if (list != null){                                         StringBuilder text = new StringBuilder();                                         for(Person person : list){                                                 text.append("\nPerson name:");                                                 text.append(person.getName());                                                 text.append("\n             age :");                                                 text.append(person.getAge());                                                 text.append("\n tel number:");                                                 text.append(person.getTelNumber());                                         }                                         inputPersonEdit.setText(text);                                 }else {                                         Toast.makeText(ServiceActivity.this, "get data error",                                                         Toast.LENGTH_SHORT).show();                                 }                         }                 }); Permission权限    如果Service在AndroidManifest.xml中声明了全局的强制的访问权限,其他引用必须声明权限才能来start,stop或bind这个service.     另外,service可以通过权限来保护她的IPC方法调用,通过调用checkCallingPermission(String)方法来确保可以执行这个操作。 AndroidManifest.xml的Service元素 <service android:name=".RemoteService" android:process=":remote">         <intent-filter>                 <action android:name="com.demo.IMyService" />         </intent-filter> </service>     这里的android:process=":remote",一开始我没有添加的,在同一个程序里使用IPC,即同一个程序作为客户端/服务器端,结果运行mRemoteService = IMyService.Stub.asInterface(service);时提示空指针异常。观察了人家的在不同程序里进行IPC的代码,也是没有这个android:process=":remote"的。后来在官方文档http://androidappdocs.appspot.com/guide/topics/manifest/service-element.html里了解到(留意第二段文字): android:processThe name of the process where the service is to run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The <application> element's process attribute can set a different default for all components. But component can override the default with its own process attribute, allowing you to spread your application across multiple processes.  If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process. If the process name begins with a lowercase character, the service will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage. 也就是说android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。 以上内容结合了不少网络文章,包括来自 http://blog.csdn.net/caowenbin的译文,http://terryblog.blog.51cto.com/1764499/382457http://4225953-163-com.iteye.com/blog/792997以及Android的官方网站文档。... 全文

Service Android 移动开发 AIDL Parcelable

Android开发 AIDL使用自定义对象作参数或返回值

默认,AIDL支持对象作参数,但需要该对象实现Parcelable接口,且aidl文件应该是该类在同一包下,需要单独给该类定义一个aidl文件.定义模型类:EnglishItem.java:... 全文

Android JAVA AIDL 远程服务

android基础笔记:服务(Service)跨进程调用Service(AIDL Service)

为了实现进程间的通信(IPC:inter process communication),Android 提供了 AIDL Service (AIDL:android interface definition language  安卓接口定义语言)1、参考:android基础笔记:服务(Service) 采用接口的方式调用本地服务的方法  文章,采用接口的方式编写一个服务;... 全文

Android Service AIDL

Android开发之黑名单来电自动挂断

          本实例允许用户动态添加号码到黑名单,并实现黑名单来电自动挂断。程序通过创建PhoneStateListener监听器来监听TelephonyManager的通话状态来实现该功能。由于自Android 10之后Android不再对外公开挂断电话的API,如果需要挂断电话必须使用AIDL与电话管理Service进行通信,并调用服务中的API实现结束电话。为了调用远程的AIDL Service,开发者需要将Android源码中的如下两个文拷到指定位置:com.android.internal.telephony包下的ITelephony.aidl... 全文

Android开发之黑名单来电自动挂断 黑名单来电自动挂断 ITelephony.aidl NeighboringCellInfo. aidl

AIDL的代码实现方式

创建aidl远程服务可以获取其他android进程的数据等,其步骤如下:1.服务端1-1.创建需要传输的数据的实体类,该类继承 Parcelable接口;1-2.创建该类的.aidl文件。其文件内容为 parcelable 类名;1-3.创建远程Ixx.aidl文件,如果该类不为普通类型,那它就必须导入,创建该文件时系统自动生成了Ixx类;1-4.创建Service子类,该类必须包含一个Stub的静态内部类。用于实现Ixx.aidl文件所声明的接口方法;1-5.在Manifest.xml文件里添加Service子类的<service>标签声明;2.客户端... 全文

android aidl.service

android跨进程通信(IPC):使用AIDL

AIDL的作用AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。 AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。选择AIDL的使用场合官方文档特别提醒我们何时使用AIDL是必要的:只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service,以及想在你的service处理多线程。如果不需要进行不同应用程序间的并发通信(IPC),you should create your interface by implementing a Binder;或者你想进行IPC,但不需要处理多线程的,则implement your interface using a Messenger。无论如何,在使用AIDL前,必须要理解如何绑定service——bindService。如何绑定服务,请参考我的另一篇文章:http://blog.csdn.net/singwhatiwanna/article/details/9058143。这里先假设你已经了解如何使用bindService。如何使用AIDL1.先建立一个android工程,用作服务端创建一个android工程,用来充当跨进程通信的服务端。2.创建一个包名用来存放aidl文件创建一个包名用来存放aidl文件,比如com.ryg.sayhi.aidl,在里面新建IMyService.aidl文件,如果需要访问自定义对象,还需要建立对象的aidl文件,这里我们由于使用了自定义对象Student,所以,还需要创建Student.aidl和Student.java。注意,这三个文件,需要都放在com.ryg.sayhi.aidl包里。下面描述如何写这三个文件。IMyService.aidl代码如下:package com.ryg.sayhi.aidl; import com.ryg.sayhi.aidl.Student; interface IMyService { List<Student> getStudent(); void addStudent(in Student student); }说明:aidl中支持的参数类型为:基本类型(int,long,char,boolean等),String,CharSequence,List,Map,其他类型必须使用import导入,即使它们可能在同一个包里,比如上面的Student,尽管它和IMyService在同一个包中,但是还是需要显示的import进来。 另外,接口中的参数除了aidl支持的类型,其他类型必须标识其方向:到底是输入还是输出抑或两者兼之,用in,out或者inout来表示,上面的代码我们用in标记,因为它是输入型参数。在gen下面可以看到,eclipse为我们自动生成了一个代理类public static abstract class Stub extends android.os.Binder implements com.ryg.sayhi.aidl.IMyService可见这个Stub类就是一个普通的Binder,只不过它实现了我们定义的aidl接口。它还有一个静态方法public static com.ryg.sayhi.aidl.IMyService asInterface(android.os.IBinder obj)这个方法很有用,通过它,我们就可以在客户端中得到IMyService的实例,进而通过实例来调用其方法。Student.aidl代码如下:package com.ryg.sayhi.aidl; parcelable Student;说明:这里parcelable是个类型,首字母是小写的,和Parcelable接口不是一个东西,要注意。Student.java代码如下:package com.ryg.sayhi.aidl; import java.util.Locale; import android.os.Parcel; import android.os.Parcelable; public final class Student implements Parcelable { public static final int SEX_MALE = 1; public static final int SEX_FEMALE = 2; public int sno; public String name; public int sex; public int age; public Student() { } public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() { public Student createFromParcel(Parcel in) { return new Student(in); } public Student[] newArray(int size) { return new Student[size]; } }; private Student(Parcel in) { readFromParcel(in); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(sno); dest.writeString(name); dest.writeInt(sex); dest.writeInt(age); } public void readFromParcel(Parcel in) { sno = in.readInt(); name = in.readString(); sex = in.readInt(); age = in.readInt(); } @Override public String toString() { return String.format(Locale.ENGLISH, "Student[ %d, %s, %d, %d ]", sno, name, sex, age); } }说明:通过AIDL传输非基本类型的对象,被传输的对象需要序列化,序列化功能java有提供,但是android sdk提供了更轻量级更方便的方法,即实现Parcelable接口,关于android的序列化,我会在以后写文章介绍。这里只要简单理解一下就行,大意是要实现如下函数 readFromParcel : 从parcel中读取对象writeToParcel :将对象写入parceldescribeContents:返回0即可Parcelable.Creator<Student> CREATOR:这个照着上面的代码抄就可以需要注意的是,readFromParcel和writeToParcel操作数据成员的顺序要一致3.创建服务端service创建一个service,比如名为MyService.java,代码如下:/** * @author scott */ public class MyService extends Service { private final static String TAG = "MyService"; private static final String PACKAGE_SAYHI = "com.example.test"; private NotificationManager mNotificationManager; private boolean mCanRun = true; private List<Student> mStudents = new ArrayList<Student>(); //这里实现了aidl中的抽象函数 private final IMyService.Stub mBinder = new IMyService.Stub() { @Override public List<Student> getStudent() throws RemoteException { synchronized (mStudents) { return mStudents; } } @Override public void addStudent(Student student) throws RemoteException { synchronized (mStudents) { if (!mStudents.contains(student)) { mStudents.add(student); } } } //在这里可以做权限认证,return false意味着客户端的调用就会失败,比如下面,只允许包名为com.example.test的客户端通过, //其他apk将无法完成调用过程 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { String packageName = null; String[] packages = MyService.this.getPackageManager(). getPackagesForUid(getCallingUid()); if (packages != null && packages.length > 0) { packageName = packages[0]; } Log.d(TAG, "onTransact: " + packageName); if (!PACKAGE_SAYHI.equals(packageName)) { return false; } return super.onTransact(code, data, reply, flags); } }; @Override public void onCreate() { Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService"); thr.start(); synchronized (mStudents) { for (int i = 1; i < 6; i++) { Student student = new Student(); student.name = "student#" + i; student.age = i * 5; mStudents.add(student); } } mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); super.onCreate(); } @Override public IBinder onBind(Intent intent) { Log.d(TAG, String.format("on bind,intent = %s", intent.toString())); displayNotificationMessage("服务已启动"); return mBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { mCanRun = false; super.onDestroy(); } private void displayNotificationMessage(String message) { Notification notification = new Notification(R.drawable.icon, message, System.currentTimeMillis()); notification.flags = Notification.FLAG_AUTO_CANCEL; notification.defaults |= Notification.DEFAULT_ALL; PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MyActivity.class), 0); notification.setLatestEventInfo(this, "我的通知", message, contentIntent); mNotificationManager.notify(R.id.app_notification_id + 1, notification); } class ServiceWorker implements Runnable { long counter = 0; @Override public void run() { // do background processing here..... while (mCanRun) { Log.d("scott", "" + counter); counter++; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }说明:为了表示service的确在活着,我通过打log的方式,每2s打印一次计数。上述代码的关键在于onBind函数,当客户端bind上来的时候,将IMyService.Stub mBinder返回给客户端,这个mBinder是aidl的存根,其实现了之前定义的aidl接口中的抽象函数。问题:问题来了,有可能你的service只想让某个特定的apk使用,而不是所有apk都能使用,这个时候,你需要重写Stub中的onTransact方法,根据调用者的uid来获得其信息,然后做权限认证,如果返回true,则调用成功,否则调用会失败。对于其他apk,你只要在onTransact中返回false就可以让其无法调用IMyService中的方法,这样就可以解决这个问题了。4. 在AndroidMenifest中声明service <service android:name="com.ryg.sayhi.MyService" android:process=":remote" android:exported="true" > <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.ryg.sayhi.MyService" /> </intent-filter> </service>说明:上述的 <action android:name="com.ryg.sayhi.MyService" />是为了能让其他apk隐式bindService,通过隐式调用的方式来起activity或者service,需要把category设为default,这是因为,隐式调用的时候,intent中的category默认会被设置为default。5. 新建一个工程,充当客户端新建一个客户端工程,将服务端工程中的com.ryg.sayhi.aidl包整个拷贝到客户端工程的src下,这个时候,客户端com.ryg.sayhi.aidl包是和服务端工程完全一样的。如果客户端工程中不采用服务端的包名,客户端将无法正常工作,比如你把客户端中com.ryg.sayhi.aidl改一下名字,你运行程序的时候将会crash,也就是说,客户端存放aidl文件的包必须和服务端一样。客户端bindService的代码就比较简单了,如下:import com.ryg.sayhi.aidl.IMyService; import com.ryg.sayhi.aidl.Student; public class MainActivity extends Activity implements OnClickListener { private static final String ACTION_BIND_SERVICE = "com.ryg.sayhi.MyService"; private IMyService mIMyService; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mIMyService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { //通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了 mIMyService = IMyService.Stub.asInterface(service); try { Student student = mIMyService.getStudent().get(0); showDialog(student.toString()); } catch (RemoteException e) { e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button1 = (Button) findViewById(R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (view.getId() == R.id.button1) { Intent intentService = new Intent(ACTION_BIND_SERVICE); intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE); } } public void showDialog(String message) { new AlertDialog.Builder(MainActivity.this) .setTitle("scott") .setMessage(message) .setPositiveButton("确定", null) .show(); } @Override protected void onDestroy() { if (mIMyService != null) { unbindService(mServiceConnection); } super.onDestroy(); } }运行效果可以看到,当点击按钮1的时候,客户端bindService到服务端apk,并且调用服务端的接口mIMyService.getStudent()来获取学生列表,并且把返回列表中第一个学生的信息显示出来,这就是整个ipc过程,需要注意的是:学生列表是另一个apk中的数据,通过aidl,我们才得到的。另外,如果你在onTransact中返回false,将会发现,获取的学生列表是空的,这意味着方法调用失败了,也就是实现了权限认证。... 全文

ipc aidl 进程间通信 service 服务

Android中的Service

        Android中的Service分为两类,一类是本地Service,一类是远程Service,访问方式也有两种,一种是startService,一种是bindService。startService和bindService的生命周期不同,如下图所示:... 全文

Android Service 本地服务 远程服务 AIDL

Android 使用Parcelable序列化对象

    Android序列化对象主要有两种方法,实现Serializable接口、或者实现Parcelable接口。实现Serializable接口是Java SE本身就支持的,而Parcelable是Android特有的功能,效率比实现Serializable接口高,而且还可以用在IPC中。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。下面就介绍一下实现Parcelable接口的方法          通过实现Parcelable接口序列化对象的步骤:          1、声明实现接口Parcelable          2、实现Parcelable的方法writeToParcel,将你的对象序列化为一个Parcel对象          3、实例化静态内部对象CREATOR实现接口Parcelable.Creator:Java代码  public static final Parcelable.Creator<T> CREATOR         其中public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。          4、完成CREATOR的代码,实现方法createFromParcel,将Parcel对象反序列化为你的对象          简而言之:通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致。                   Parcel对象可以通过以下方法写入或读取byte, double, float, int, long, String这6种类型变量。 Java代码  writeByte(byte), readByte()  writeDouble(double), readDouble()  writeFloat(float), readFloat()  writeInt(int), readInt()  writeLong(long), readLong()  writeString(String), readString()          也可以读取或写入他们的数组 Java代码  writeBooleanArray(boolean[]), readBooleanArray(boolean[]), createBooleanArray()  writeByteArray(byte[]), writeByteArray(byte[], int, int), readByteArray(byte[]), createByteArray()  writeCharArray(char[]), readCharArray(char[]), createCharArray()  writeDoubleArray(double[]), readDoubleArray(double[]), createDoubleArray()  writeFloatArray(float[]), readFloatArray(float[]), createFloatArray()  writeIntArray(int[]), readIntArray(int[]), createIntArray()  writeLongArray(long[]), readLongArray(long[]), createLongArray()  writeStringArray(String[]), readStringArray(String[]), createStringArray()  writeSparseBooleanArray(SparseBooleanArray), readSparseBooleanArray()          更多操作可以参阅: http://developer.android.com/reference/android/os/Parcel.html  示例代码: Java代码  package com.ipjmc.demo.parcelable;      import java.util.Date;    import android.os.Parcel;  import android.os.Parcelable;    public class ParcelableDate implements Parcelable { //声明实现接口Parcelable        //这里定义了两个变量来说明读和写的顺序要一致      public long mId;      public Date mDate;            public ParcelableDate(long id, long time) {          mId = id;          mDate = new Date(time);      }            public ParcelableDate(Parcel source) {          //先读取mId,再读取mDate          mId = source.readLong();          mDate = new Date(source.readLong());      }            @Override      public int describeContents() {          return 0;      }        //实现Parcelable的方法writeToParcel,将ParcelableDate序列化为一个Parcel对象      @Override      public void writeToParcel(Parcel dest, int flags) {           //先写入mId,再写入mDate          dest.writeLong(mId);          dest.writeLong(mDate.getTime());      }        //实例化静态内部对象CREATOR实现接口Parcelable.Creator      public static final Parcelable.Creator<ParcelableDate> CREATOR = new Creator<ParcelableDate>() {                    @Override          public ParcelableDate[] newArray(int size) {              return new ParcelableDate[size];          }                    //将Parcel对象反序列化为ParcelableDate          @Override          public ParcelableDate createFromParcel(Parcel source) {              return new ParcelableDate(source);          }      };  }  ... 全文

Android AIDL JAVA service 绑定远程服务

Android开发学习笔记:Service的远程调用

   在Andorid平台中,各个组件运行在自己的进程中,他们之间是不能相互访问的,但是在程序之间是不可避免的要传递一些对象,在进程之间相互通信。为了实现进程之间的相互通信,Andorid采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信,并且Android通过接口定义语言(Andorid Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码,例如,你在Activity里的代码需要访问Service中的一个方法,那么就可以通过这种方式来实现了。   AIDL是Android的一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。... 全文

Service Android 移动开发 AIDL 休闲

android之远程服务的调用

  今天研究了一下android中的RPC模式(Remote Procedure Call 远程进程调用)。颇有心得,所以记录下来。方便大家使用......简单的描述一下定义的相关内容,给大家补充点知识。... 全文

android RPC aidl 不同进程之间的互相访问 移动开发

1