摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处。

在上一篇中我们学习了Android Service相关的许多基础但是重要的内容,基本涵盖大部分平日里的开发工作。今天我们继续学习一下稍微高级一点的用法,即:远程Service用法,使用远程Service可以实现安卓跨进程通信的功能。下面我们就开始学习一下吧。

什么是远程Service?

所谓的远程Service就是与调用者不在同一进程的Service即可叫做远程Service。那是不是也有近程Service?其实不叫近程Service,专业叫法叫做本地Service,就是调用者与Service在同一进程。

调用远程Service的桥梁-AIDL接口定义语言

由于远程服务与调用者不在同一进程,我们不能再像调用本地服务一样的方式去调用远程服务,

那么如何才能让Activity与一个远程Service建立关联呢?这就要使用AIDL来进行跨进程通信了(IPC)。

AIDL(Android Interface Definition Language)是Android接口定义语言的意思,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。(本篇着重讲解与远程服务通信的过程,不涉及AIDL接口定义语言的细节讲解)

废话少说,下面我们通过一个简单的Demo来讲解一下与远程Service通信的过程。

首先我们新建一个远程服务Demo的工程,新建RemoteService.aidl文件,代码如下:

1 package com.wl.remoteservice;
2 interface RemoteService{
3     int call(int a,int b);
4 }

我们点击完保存之后,在gen目录下会生成一个与之对应的java文件,如下:

关于文件中内容我们暂时不细究,会在下篇的时候在研究一下。

然后编写Service类,新建WLService继承Service,如下:

 1 public class WLService extends Service {
 2
 3     private static final String TAG = "HEART";
 4     @Override
 5     public IBinder onBind(Intent intent) {
 6         Log.i(TAG, "onBind");
 7         return new MyBinder();
 8     }
 9
10     private int methodInRemoteService(int a,int b){
11
12         return a+b;
13     }
14
15     private class MyBinder extends RemoteService.Stub{
16
17         @Override
18         public int call(int a,int b) {
19
20             return methodInRemoteService(a,b);
21         }
22     }
23
24     @Override
25     public void onCreate() {
26         Log.i(TAG, "onCreate");
27         super.onCreate();
28     }
29
30     @Override
31     public boolean onUnbind(Intent intent) {
32         Log.i(TAG, "onUnbind");
33         return super.onUnbind(intent);
34
35     }
36     @Override
37     public void onDestroy() {
38         Log.i(TAG, "onDestroy");
39         super.onDestroy();
40     }
41
42 }

这里我们定义了一个内部类MyBinder继承自RemoteService.Stub,那这个stub是什么玩意呢?点进去看一下,如下

1 public static abstract class Stub extends android.os.Binder implements com.wl.remoteservice.RemoteService

看定义我们就明白了,原来MyBinder就是Binder子类并且实现了RemoteService接口,所以在onBind的时候返回其实例也就容易理解了。

接下来,在清单文件注册Service。这里我们需要在另一个应用程序启动WLService,但是在另一个应用程序中去绑定Service的时候并没有WLService这个类,这时就必须使用到隐式Intent了。现在修改AndroidManifest.xml中的代码,给WLService加上一个action,如下所示:

1         <service android:name="com.wl.remoteservice.WLService">
2             <intent-filter >
3                 <action android:name="com.wanglei.remoteservice"/>
4             </intent-filter>
5         </service>

然后我们新建一个项目用以调用上面项目中的远程服务,新项目就叫做:调用远程服务。

首先需要将RemoteService.aidl拷贝过来,记住需要连同原包路径一同拷贝过来,如下:

接下来,修改布局文件:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     tools:context=".MainActivity" >
 7
 8     <Button
 9         android:layout_width="fill_parent"
10         android:layout_height="wrap_content"
11         android:onClick="bind"
12         android:text="绑定服务" />
13
14     <Button
15         android:layout_width="fill_parent"
16         android:layout_height="wrap_content"
17         android:onClick="unbind"
18         android:text="解除绑定服务" />
19
20     <Button
21         android:layout_width="fill_parent"
22         android:layout_height="wrap_content"
23         android:onClick="click"
24         android:text="调用远程服务方法" />
25
26 </LinearLayout>

然后编写MainActivity中代码,如下:

 1 public class MainActivity extends Activity {
 2     private static final String TAG = "HEART";
 3     private RemoteService mRemoteService;
 4     private MyConn conn;
 5
 6     @Override
 7     protected void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.activity_main);
10     }
11
12     public void bind(View view){
13         Intent intent = new Intent();
14         intent.setAction("com.wanglei.remoteservice");
15         conn = new MyConn();
16         bindService(intent, conn, BIND_AUTO_CREATE);//异步的操作
17     }
18
19     public void unbind(View view){
20         unbindService(conn);
21     }
22
23     public void click(View view){
24
25         if(null != mRemoteService){
26             try {
27                 int result = mRemoteService.call(10,20);
28                 Log.i(TAG, "result = "+result);
29             } catch (RemoteException e) {
30                 e.printStackTrace();
31             }
32         }
33     }
34
35     private class MyConn implements ServiceConnection{
36         @Override
37         public void onServiceConnected(ComponentName name, IBinder service) {
38
39             mRemoteService = RemoteService.Stub.asInterface(service);
40         }
41
42         @Override
43         public void onServiceDisconnected(ComponentName name) {
44
45         }
46     }
47 }

会发现和上篇讲的bind服务差别不大,这里我们需要在另一程序里面绑定服务所以需要用隐式意图开启。

这里我们需要注意一下,在安卓5.0出来以后,服务意图必须用显式调用,调用bind服务的时候会报如下警告

我们找一下源码,看看哪里报的这个警告,终于在 sdk/sources/android-21/android/app/ContextImpl.Java目录下找到报警告的代码:

 1     private void validateServiceIntent(Intent service) {
 2         if (service.getComponent() == null && service.getPackage() == null) {
 3             if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
 4                 IllegalArgumentException ex = new IllegalArgumentException(
 5                         "Service Intent must be explicit: " + service);
 6                 throw ex;
 7             } else {
 8                 Log.w(TAG, "Implicit intents with startService are not safe: " + service
 9                         + " " + Debug.getCallers(2, 3));
10             }
11         }
12     }

好了找到报错的原因了,那怎么解决呢?观察源码发现最外层if判断的时候有个service.getPackage() == null,我们只需要使其不为null不就可以了,这也是谷歌推荐的解决方法

我们将绑定服务的方法改为如下:

1 public void bind(View view){
2         Intent intent = new Intent();
3         intent.setAction("com.wanglei.remoteservice");
4         intent.setPackage("com.wl.remoteservice");//设置为Service所在包名
5         conn = new MyConn();
6         bindService(intent, conn, BIND_AUTO_CREATE);//异步的操作
7 }

这样修改就好了,当然还有另外一种解决方法,将隐式意图变为显示意图,方法如下:

 1
 2 public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
 3         // Retrieve all services that can match the given intent
 4         PackageManager pm = context.getPackageManager();
 5         List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
 6         // Make sure only one match was found
 7         if (resolveInfo == null || resolveInfo.size() != 1) {
 8             return null;
 9         }
10         // Get component info and create ComponentName
11         ResolveInfo serviceInfo = resolveInfo.get(0);
12         String packageName = serviceInfo.serviceInfo.packageName;
13         String className = serviceInfo.serviceInfo.name;
14         ComponentName component = new ComponentName(packageName, className);
15         // Create a new intent. Use the old one for extras and such reuse
16         Intent explicitIntent = new Intent(implicitIntent);
17         // Set the component to be explicit
18         explicitIntent.setComponent(component);
19         return explicitIntent;
20     } 

好了,通过以上两种方式就可以解决了,到此我们两个项目都已经编写完毕,先运行远程服务demo项目,在运行调用远程服务项目,点击绑定远程服务按钮,然后点击调用远程服务按钮,打印如下:

到此为止,我们成功调用了远程服务中的方法,跨进程通信成功实现,不过有些刚接触的同学可能还有些混乱,怎么觉得那么混乱,比平时用的组建多那么多步骤,那我们总结一下调用远程服务的步骤:

1.编写aidl文件

2.创建远程服务类,在服务的内部创建一个内部类提供一个方法,可以间接调用服务的方法

3.实现服务的onbind方法,返回服务内部类实例

4.拷贝aidl文件到另一工程联同包名

5.在activity 绑定服务。bindService();

6.在服务成功绑定的时候 会执行一个方法 onServiceConnected 传递过来一个 IBinder对象进行类型转换

7.调用远程服务里面的方法。

好了,到这里关于服务的所有最重要的部分都已经讲解完了,通过(上)(中)两篇相信你对服务有了一个全面的认识。

转载于:https://www.cnblogs.com/leipDao/p/7365570.html

安卓Service完全解析(中)相关推荐

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

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

  2. dns提供商主机名_在 Kubernetes 中使用 DNS 和 Headless Service 发现运行中的 Pod

    作者:Mattias te Wierik 翻译:Bach(才云) 校对:星空下的文仔(才云).bot(才云) 在 Kubernetes 集群中,Service 是将运行在一组 Pods 上的应用程序公 ...

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

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

  4. Android 项目开发 基于Web Service 服务的中英翻译软件(三) Web Service服务 Ksoap2 项目...

    关于Web Service Android 应用通常是运行手机平台上,手机系统的硬件资源远远比不上PC平台,不管是存储能力还是计算能力,在Android平台上运行一些小的应用时可能的,但对于需要进行大 ...

  5. 安卓学习之解析json数据

    安卓学习之解析json数据 文章目录 安卓学习之解析json数据 前言 一.Json数据 二.使用原始的JsonObject来解析 1.请求数据 2.解析数据 2.1JsonObject解析数据 2. ...

  6. Web Service详细解析及使用方法

    Web Service详细解析及使用方法 XFire篇.... 2 XFire简介... 2 XFire特性... 2 XFire使用... 3 提供服务实现类... 3 服务类的接口类... 3 配 ...

  7. 安卓Service 详解

     Service全部内容基本会在本篇涉及到,我们将围绕以下主要知识点进行分析: Service简单概述 Service在清单文件中的声明 Service启动服务实现方式及其详解 Service绑定服务 ...

  8. WR:微生物污染源解析中宿主特异性标记物在中国的表现特征

    WR:微生物污染源解析中宿主特异性标记物在中国的表现特征 微生物污染源解析中宿主特异性标记物在中国的表现特征 Performance of host-associated genetic marker ...

  9. SQL Server 2000 Service Pack 4 中所修复的 bug 的列表

    有关在 SQL Server 2000 Service Pack 4 已修复的 bug 的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 314128  FIX: 一 ...

最新文章

  1. 扩增子分析解读1质控,实验设计,双端序列合并
  2. 《Redis官方文档》用Redis构建分布式锁(悲观锁)
  3. [基础知识]Linux新手系列之三
  4. matlab程序svm四等级分类,支持向量机(SVM)多分类matlab程序代码
  5. android studio 优化完以后开不了虚拟机,Android studio 打不开官方虚拟机 100%成功解决方法...
  6. python使用random生成不重复的随机数
  7. php 处理tiff,TIFF图像文件(五):LZW的PHP应用
  8. web前端工程师眼中的母亲节
  9. 语音关键词检索实验小结
  10. uni-app 微信小程序实现全屏悬浮按钮可拖动,自动吸附边缘
  11. Python-函数入参和全局变量
  12. python爬取京东评论分析_Python爬取京东商品评价(动态网页的爬取)
  13. adblockplus简单介绍
  14. MySQL5.7卸载不干净,残留文件MySQL connector net 8.0.12
  15. 【AI每日播报】三星发布AI助手 谷歌打造超速人工智能媲美人类
  16. Android 代码新增联系人至手机通讯录中
  17. linux安装Zeppelin
  18. JAVA中级之图形界面
  19. 2013年9月移动客户端病毒报告
  20. xenapp6.5上安装完smartauditor后,Appcenter检测失败

热门文章

  1. java中的与或运算
  2. Unity 3D 正交相机(Orthographic)
  3. 简单的企业网站后台的实现之流程
  4. poj 2417 Discrete Logging
  5. 关于本博客的feed订阅
  6. 利用国内镜像加快pip下载速度和成功率
  7. HihoCoder-1174拓扑排序
  8. 60后即将退休的人,有多少存款就算富有了?
  9. 浙江哪个地方的杨梅最出名?
  10. 人人想健康!但,健康的,最主要因素,是什么?