首先,大概来总结一下与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

Android Service实现双向通信(一)的更多相关文章

  1. android service两种启动方式

    android service的启动方式有以下两种: 1.Context.startService()方式启动,生命周期如下所示,启动时,startService->onCreate()-> ...

  2. 1、Android Studio集成极光推送(Jpush) 报错 java.lang.UnsatisfiedLinkError: cn.jpush.android.service.PushProtoco

    Android studio 集成极光推送(Jpush) (华为手机)报错, E/JPush: [JPushGlobal] Get sdk version fail![获取sdk版本失败!] W/Sy ...

  3. Android Service完全解析,关于服务你所需知道的一切(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

  4. Android Service完全解析,关于服务你所需知道的一切(上)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的A ...

  5. android service 的各种用法(IPC、AIDL)

    http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...

  6. Android service介绍和启动方式

    1.Android service的作用: service通常是用来处理一些耗时操作,或后台执行不提供用户交互界面的操作,例如:下载.播放音乐. 2.Android service的生命周期: ser ...

  7. Android Service初始

    一.Service概念 1.Service是一个应用程序组件 2.Service没有图像化界面 3.Service通常用来处理一些耗时比较长的操作 4.可以使用Service更新ContentProv ...

  8. Android Service与Thread的区别

    Android Service,后台,Android的后台就是指,它的运行是完全不依赖UI的.即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行.比如说一些应用程序 ...

  9. Android service binder aidl 关系

    /********************************************************************************** * Android servic ...

随机推荐

  1. HDU 4605 Magic Ball Game 主席树

    题意: 给一棵\(n(1 \leq n \leq 10^5)\)个节点的二叉树,除叶子节点外,每个点都有左儿子和右儿子. 每个点上都有一个权值. 游戏规则是这样的:在根节点放一个权值为\(X\)的小球 ...

  2. tar.xz结尾的文件的解压缩方法

    例如: codeblocks-13.12-1_i386.debian.stable.tar 这个压缩包也是两层压缩,外面是xz压缩方式,里层是tar压缩方式. 解压缩方法: $xz -d ***.ta ...

  3. 《机器学习实战》笔记——AdaBoost

    笔记见备注 # _*_ coding:utf-8 _*_ from numpy import * # 简单数据集 def loadSimpData(): datMat = matrix([[1., 2 ...

  4. 爬虫Scrapy框架-2爬取网站视频详情

     爬取视频详情:http://www.id97.com/ 创建环境: movie.py 爬虫文件的设置: # -*- coding: utf-8 -*- import scrapy from movi ...

  5. “玲珑杯”线上赛 Round #17 河南专场

    闲来无事呆在寝室打打题,没有想到还有中奖这种操作,超开心的 玲珑杯”线上赛 Round #17 河南专场 Start Time:2017-06-24 12:00:00 End Time:2017-06 ...

  6. spl_autoload_register和__autoload

    1.实例化一个未定义的类时会触发 2.类存在继承关系时,被继承的类没有引入的情况下,会触发 (继承关系的两个类必须在同一个目录下)  __autoload 实例化PRINTIT类,'PRINTIT'作 ...

  7. 九度oj 题目1080:进制转换

    题目描述: 将M进制的数X转换为N进制的数输出. 输入: 输入的第一行包括两个整数:M和N(2<=M,N<=36). 下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成 ...

  8. 九度oj 题目1466:排列与二进制

    题目描述: 在组合数学中,我们学过排列数.从n个不同元素中取出m(m<=n)个元素的所有排列的个数,叫做从n中取m的排列数,记为p(n, m).具体计算方法为p(n, m)=n(n-1)(n-2 ...

  9. hdu5730 Shell Necklace 【分治fft】

    题目 简述: 有一段长度为n的贝壳,将其划分为若干段,给出划分为每种长度的方案数,问有多少种划分方案 题解 设\(f[i]\)表示长度为\(i\)时的方案数 不难得dp方程: \[f[i] = \su ...

  10. 【python自动化】python 常用时间获取方法

    代码如下: import datetime import time DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" DATE_FORMAT = &quo ...