安卓Service完全解析(中)
摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处。
在上一篇中我们学习了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完全解析(中)相关推荐
- Android Service完全解析,关于服务你所需知道的一切(下)
转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...
- dns提供商主机名_在 Kubernetes 中使用 DNS 和 Headless Service 发现运行中的 Pod
作者:Mattias te Wierik 翻译:Bach(才云) 校对:星空下的文仔(才云).bot(才云) 在 Kubernetes 集群中,Service 是将运行在一组 Pods 上的应用程序公 ...
- Android Service完全解析,关于服务你所需知道的一切(上)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的A ...
- Android 项目开发 基于Web Service 服务的中英翻译软件(三) Web Service服务 Ksoap2 项目...
关于Web Service Android 应用通常是运行手机平台上,手机系统的硬件资源远远比不上PC平台,不管是存储能力还是计算能力,在Android平台上运行一些小的应用时可能的,但对于需要进行大 ...
- 安卓学习之解析json数据
安卓学习之解析json数据 文章目录 安卓学习之解析json数据 前言 一.Json数据 二.使用原始的JsonObject来解析 1.请求数据 2.解析数据 2.1JsonObject解析数据 2. ...
- Web Service详细解析及使用方法
Web Service详细解析及使用方法 XFire篇.... 2 XFire简介... 2 XFire特性... 2 XFire使用... 3 提供服务实现类... 3 服务类的接口类... 3 配 ...
- 安卓Service 详解
Service全部内容基本会在本篇涉及到,我们将围绕以下主要知识点进行分析: Service简单概述 Service在清单文件中的声明 Service启动服务实现方式及其详解 Service绑定服务 ...
- WR:微生物污染源解析中宿主特异性标记物在中国的表现特征
WR:微生物污染源解析中宿主特异性标记物在中国的表现特征 微生物污染源解析中宿主特异性标记物在中国的表现特征 Performance of host-associated genetic marker ...
- SQL Server 2000 Service Pack 4 中所修复的 bug 的列表
有关在 SQL Server 2000 Service Pack 4 已修复的 bug 的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章: 314128 FIX: 一 ...
最新文章
- 扩增子分析解读1质控,实验设计,双端序列合并
- 《Redis官方文档》用Redis构建分布式锁(悲观锁)
- [基础知识]Linux新手系列之三
- matlab程序svm四等级分类,支持向量机(SVM)多分类matlab程序代码
- android studio 优化完以后开不了虚拟机,Android studio 打不开官方虚拟机 100%成功解决方法...
- python使用random生成不重复的随机数
- php 处理tiff,TIFF图像文件(五):LZW的PHP应用
- web前端工程师眼中的母亲节
- 语音关键词检索实验小结
- uni-app 微信小程序实现全屏悬浮按钮可拖动,自动吸附边缘
- Python-函数入参和全局变量
- python爬取京东评论分析_Python爬取京东商品评价(动态网页的爬取)
- adblockplus简单介绍
- MySQL5.7卸载不干净,残留文件MySQL connector net 8.0.12
- 【AI每日播报】三星发布AI助手 谷歌打造超速人工智能媲美人类
- Android 代码新增联系人至手机通讯录中
- linux安装Zeppelin
- JAVA中级之图形界面
- 2013年9月移动客户端病毒报告
- xenapp6.5上安装完smartauditor后,Appcenter检测失败