Android Service是分为两种:

  本地服务(Local Service): 同一个apk内被调用
  远程服务(Remote Service):被另一个apk调用
 
远程服务需要借助AIDL来完成。

 AIDL 是什么
  AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
  AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。
AIDL 的作用
  由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。
  通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作。
选择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://www.cnblogs.com/lonkiss/archive/2012/10/23/2735548.html

下面用一个客户端Activity操作服务端Service播放音乐的实例演示AIDL的使用。
服务端代码结构(左)                                 客户端代码结构(右)

  被标记的就是需要动手的。

服务端
新建一个android application project,命名为PlayerServer。 在res下的raw文件夹里面放入一个音乐文
件,我这里放入的是Delta Goodrem的《Lost Without You》片段。如果不存在raw这个文件夹就自己新建一
个,命名为raw。这个文件夹在raw文件夹下,与layout文件夹平级。raw中的文件遵守标识符的命名规则,不
要出现中文和空格,多个单词可以用下划线连接。
新建一个IRemoteServiice.aidl 文件,加入如下代码

package pandafang.demo.playerserver;
interface IRemoteService {void play();void stop();
}
可见aidl文件的代码跟java的interface一样,但是aidl中不能加public等修饰符。Ctrl + S 保存后 ADT 会根据这
个IRemoteService.aidl文件自动生成IRemoteService.java文件。如同R.java文件一样在“gen/包名”下,代码是
自动生成的,不要手动修改。
接下来就是bound service的知识了。IRemoteService.java 中有一个Stub静态抽象类extends Binder 
implements IRemoteService。自己动手写一个PlayerService 用来播放音乐,播放音乐需要使用
android.media.MediaPlayer类。代码如下
/*** 播放音乐的服务*/
public class PlayerService extends Service {public static final String TAG = "PlayerService";private MediaPlayer mplayer;@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG,"service onbind");if(mplayer==null){// 方法一说明// 此方法实例化播放器的同时指定音乐数据源 ,若用此方法在,mplayer.start() 之前不需再调用mplayer.prepare() // 官方文档有说明 :On success, prepare() will already have been called and must not be called again.// 译文:一旦create成功,prepare已被调用,勿再调用 。查看源代码可知create方法内部已经调用prepare方法。// 方法一开始// mplayer = MediaPlayer.create(this, R.raw.lost);// 方法一结束// 方法二说明// 若用此方法,在mplayer.start() 之前需要调用mplayer.prepare() // 方法二开始mplayer = new MediaPlayer();try {FileDescriptor fd = getResources().openRawResourceFd(R.raw.lost).getFileDescriptor(); // 获取音乐数据源mplayer.setDataSource(fd); // 设置数据源mplayer.setLooping(true); // 设为循环播放} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 方法二结束Log.i(TAG,"player created");}return mBinder;}// 实现aidl文件中定义的接口private IBinder mBinder = new IRemoteService.Stub() {@Overridepublic void stop() throws RemoteException {try {if (mplayer.isPlaying()) {mplayer.stop();}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}@Overridepublic void play() throws RemoteException {try {if (mplayer.isPlaying()) {return;}// start之前需要prepare。// 如果前面实例化mplayer时使用方法一,则第一次play的时候直接start,不用prepare。// 但是stop一次之后,再次play就需要在start之前prepare了。// 前面使用方法二 这里就简便了, 不用判断各种状况mplayer.prepare();mplayer.start();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}};@Overridepublic boolean onUnbind(Intent intent) {if (mplayer != null) {mplayer.release();}Log.i(TAG,"service onUnbind");return super.onUnbind(intent);}}

 服务编写好以后,按照惯例在AndroidManifest.xml中加入声明,代码如下

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="pandafang.demo.playerserver"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="15" /><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><service android:name=".PlayerService" android:process=":remote"><intent-filter ><action android:name="com.example.playerserver.PlayerService"/></intent-filter></service></application></manifest>

需要加入的只是<service>...</service>那段,要注意的是 android:process=":remote" 和 intent-filter 。

  运行服务端到设备上,准备给客户端调用

客户端

  新建一个android application project,命名为PlayerClient。将服务端放有aidl文件的包直接copy到客户

端src目录下,保留包中的aidl文件,其他删除。

 编写MainActivity.java 代码如下

/*** 客户端控制界面*/
public class MainActivity extends Activity {public static final String TAG = "MainActivity";// 服务端 AndroidManifest.xml中的intent-filter action声明的字符串public static final String ACTION = "com.example.playerserver.PlayerService";private Button playbtn, stopbtn;private IRemoteService mService;private boolean isBinded = false;private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {isBinded = false;mService = null;}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mService = IRemoteService.Stub.asInterface(service);isBinded = true;}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);doBind();initViews();}private void initViews() {playbtn = (Button) findViewById(R.id.button1);stopbtn = (Button) findViewById(R.id.button2);playbtn.setOnClickListener(clickListener);stopbtn.setOnClickListener(clickListener);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}@Overrideprotected void onDestroy() {doUnbind();super.onDestroy();}public void doBind() {Intent intent = new Intent(ACTION);bindService(intent, conn, Context.BIND_AUTO_CREATE);}public void doUnbind() {if (isBinded) {unbindService(conn);mService = null;isBinded = false;}}private OnClickListener clickListener = new OnClickListener() {@Overridepublic void onClick(View v) {if (v.getId() == playbtn.getId()) {// playLog.i(TAG,"play button clicked");try {mService.play();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}} else {// stopLog.i(TAG,"stop button clicked");try {mService.stop();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};}

MainActivity是根据向导自动生成的,不需要在AndroidManifest.xml中注册声明了

  运行客户端到设备,按下按钮可以播放/停止 效果如图

如果想对更加详细的实现原理进行研究,可以参见这篇文章:

http://www.cnblogs.com/over140/archive/2011/03/08/1976890.html

Android 进程间通信 实例分析相关推荐

  1. Android架构实例分析之编写hello驱动的HAL层代码

    Android架构实例分析之编写hello驱动的HAL层代码 摘要: HAL层中文名称又叫硬件抽象层,可以理解我Linux驱动的应用层.本文实现了一个简单的hello HAL的代码,衔接hello驱动 ...

  2. Android ANR 实例分析

    什么是ANR? 以下四个条件都可以造成ANR发生: InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件 BroadcastQueue Timeout :在执行前 ...

  3. android 4实例分析,OpenGL Shader实例分析(4)闪光效果

    本文实例为大家分享了opengl shader实例闪光效果的具体代码,供大家参考,具体内容如下 在游戏中,当战斗结束后,对一些获取的宝贝需要进行闪光处理.这篇文章介绍一个进行闪光处理的shader,运 ...

  4. Android从驱动到应用开发实例分析

    Android从驱动到应用开发实例分析 1. 第一个android应用程序 Android应用一般包含一个源代码目录src.一个资源目录res.一个配置文件AndroidManifest.xml.和一 ...

  5. Android Touch事件原理加实例分析

    Android中有各种各样的事件,以响应用户的操作.这些事件可以分为按键事件和触屏事件.而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制. ...

  6. Android开发中StackOverflowError错误实例分析

    http://blog.csdn.net/mozhizun/article/details/7051300 http://blog.csdn.net/gaomatrix/article/details ...

  7. 转 android anr 分析示例,[摘]Android ANR日志分析指南之实例解析

    前文<[摘]Android ANR日志分析指南>也摘抄了如何分析,接下来通过实例解析. 一.主线程被其他线程lock,导致死锁 waiting on <0x1cd570> (a ...

  8. Android串口通信实例分析【附源码】

    Android 串口通信实例分析,用的时开源的android-serialport-api 这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖- ...

  9. Android中list常用方法,Android中ListActivity用法实例分析

    本文实例分析了Android中ListActivity用法.分享给大家供大家参考,具体如下: 程序如下: import android.app.ListActivity; import android ...

最新文章

  1. 2020年AI产业报告:100个岗位抢1个人,计算机视觉成最大缺口
  2. C++静态全局变量问题
  3. Hexo瞎折腾系列(5) - 使用hexo-neat插件压缩页面静态资源
  4. 使用DDD、事件风暴和Actor来设计反应式系统
  5. 20道C#练习题(一)1——10题
  6. 如何通过 Tampermonkey 快速查找 JavaScript 加密入口
  7. 装饰效果(最大连续字段和)
  8. gdb进行多线程调试
  9. Linq 支持动态字查询集合, 也就是说根据传入的值进行查询。
  10. 小米蓝牙耳机驱动_硬核拆解——小米蓝牙耳机
  11. 我行我素购物管理系统(面向对象)
  12. msfconsole使用手册
  13. Java通过GeoLite2-City.mmdb进行IP信息查询地理定位和经纬度
  14. 阿里云MQTT使用教程
  15. 0.0.0.0/0是什么意思
  16. Java 多线程学习(4)浅析 LongAdder、LongAccumulator 和 Striped64 的底层实现原理
  17. java学习视频分享
  18. 计算机领域的顶会、顶刊
  19. java sci论文,SCI论文中那些容易被混淆的部分!你写错过吗?
  20. 软件导刊三审被退稿_【软件导刊】省级期刊_计算机杂志_91学术

热门文章

  1. java中创建对象的方式
  2. log4j在javaWeb项目中的使用
  3. MySQL 数据库常用命令—insert delete update select
  4. Zygote进程启动流程分析
  5. 人工智能大牛的新年启示:未来要看无监督学习、自然语言处理
  6. 读书笔记 effective c++ Item 50 了解何时替换new和delete 是有意义的
  7. 分布式锁的几种实现方式
  8. 提升 DevOps 效率,试试 ChatOps 吧!
  9. string用法总结
  10. 【C语言探索之旅】 第一部分第六课:条件表达式