首先,大概来总结一下与Service的通信方式有很多种:

  1. 通过BroadCastReceiver:这种方式是最简单的,只能用来交换简单的数据;
  2. 通过Messager:这种方式是通过一个传递一个Messager给对方,通过这个它来发送Message对象。这种方式只能单向传递数据。可以是ServiceActivity,也可以是从Activity发送数据给Service。一个Messeger不能同时双向发送;
  3. 通过Binder来实现远程调用(IPC):这种方式是Android的最大特色之一,让你调用远程Service的接口,就像调用本地对象一样,实现非常灵活,写起来也相对复杂。

本文最重点谈一下怎么使用AIDL实现Service端和Client端的双向通信(或者叫"调用")。

首先定义一个AIDL接口如下:

// IRemoteService.aidl
package com.race604.servicelib; interface IRemoteService {
int someOperate(int a, int b);
}

这里只定义了一个简单的接口someOperate(),输入参数ab,返回一个int值。

Service的实现如下:

// RemoteService.java
package com.race604.remoteservice; import ... public class RemoteService extends Service {
private static final String TAG = RemoteService.class.getSimpleName();
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int someOperate(int a, int b) throws RemoteException {
Log.d(TAG, "called RemoteService someOperate()");
return a + b;
}
}; @Override
public IBinder onBind(Intent intent) {
return mBinder; // 注意这里返回binder
}
}

这里,在RemoteService里面实现一个IRemoteService.Stub接口的Binder,并且在onBind()中返回此Binder对象。 在AndroidManifest.xmlRemoteService的申明如下:

<service
android:name=".RemoteService"
android:enabled="true"
android:exported="true" > <intent-filter>
<action android:name="com.race604.servicelib.IRemoteService" />
</intent-filter>
</service>

这里android:exported="true"表示可以让其他进程绑定,这里还有一个<action android:name="com.race604.servicelib.IRemoteService" />,这里是为了让后面的Client通过此Action来绑定。

Client的调用方法如下:

package com.race604.client;

import ...

public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    private static final String TAG = MainActivity.class.getSimpleName();
private IRemoteService mService; private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(MainActivity.this, "Service connected", Toast.LENGTH_SHORT).show();
mService = IRemoteService.Stub.asInterface(service);
} @Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(MainActivity.this, "Service disconnected", Toast.LENGTH_SHORT).show();
mService = null;
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); findViewById(R.id.bind).setOnClickListener(this);
findViewById(R.id.unbind).setOnClickListener(this);
findViewById(R.id.call).setOnClickListener(this);
} private void callRemote() { if (mService != null) {
try {
int result = mService.someOperate(1, 2);
Toast.makeText(this, "Remote call return: " + result, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(this, "Remote call error!", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Service is not available yet!", Toast.LENGTH_SHORT).show();
}
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bind:
Intent intent = new Intent(IRemoteService.class.getName());
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
break;
case R.id.unbind:
unbindService(mServiceConnection);
break;
case R.id.call:
callRemote();
break;
}
}
}

在客户端,使用Context.bindService()函数,绑定到远程的Service。注意到这里的Intent intent = new Intent(IRemoteService.class.getName());,和上面的Service申明的Action一致。BIND_AUTO_CREATE这个Flag从名字就能看出,表示如果Bind的时候,如果还没有Service的实例,就自动创建。
这里有一个地方需要注意,在Android 5.0以后,就不允许使用非特定的Intent来绑定Service了,需要使用如下方法:

Intent intent = new Intent(IRemoteService.class.getName());
intent.setClassName("com.race604.remoteservice", "com.race604.remoteservice.RemoteService");
// 或者setPackage()
// intent.setPackage("com.race604.remoteservice");
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

到这里就基本实现了一个完整的Client调用远程Service的实例了。

源代码可以参考这个Commit

最新文章

  1. 2016年最新mac下vscode配置golang开发环境支持debug
  2. OC之从键盘输入NSString字符串
  3. Oracle 监听器日志文件过大导致监听异常
  4. Android控件之MultiAutoCompleteTextView(自动匹配输入的内容)
  5. poj 2923(状态压缩dp)
  6. 采用thinkphp框架实现添加管理员功能
  7. ASP.NET MVC 音乐商店 - 目录
  8. 在IE6里面当元素浮动后再设置margin那么就会产生双倍边距
  9. Android学习之Service(1)---&gt;Started方式
  10. ueditor图片无法左右对齐的解决
  11. 给大家安利一个学习angular2的视频网站
  12. Go:学习笔记兼吐槽(3)
  13. 目标检测算法(1)目标检测中的问题描述和R-CNN算法
  14. oracle监听的动态注册和静态注册
  15. 《HTTP 权威指南》笔记:第十六章&amp;第十七章 国际化、内容协商与转码
  16. LabVIEW(十一):条件结构的巧用
  17. mysqldump导出数据时,某些表不导出,排除某些表,不导出某些表
  18. *args和**kwargs在python中的作用
  19. mac电脑的系统偏好设置的安全与隐私的任何来源没有了
  20. 基础回顾—list遍历4种

热门文章

  1. CodeForces 500E New Year Domino
  2. UVa 10564 DP Paths through the Hourglass
  3. JS实现——贪吃蛇
  4. I love you
  5. foy: 轻量级的基于 nodejs 的通用 build 工具
  6. 0014.Linux环境搭建 Python环境搭建
  7. JAVA调用oracle存储过程实例
  8. 设计模式(二 &amp; 三)工厂模式:2-工厂方法模式
  9. iOS------主题设置--&gt;Appearance
  10. 【Luogu】P2765魔术球问题(没看懂的乱搞)