AIDL 进程间的通信(一)
来源:互联网 发布:网络语吃鸡是什么意思 编辑:程序博客网 时间:2024/06/03 05:30
一、前言
通过上一篇的Service基本介绍,相信大家有了初步的认识了,如果你还没见看过前面那篇文章,可以先阅读一下:Service 基本介绍 http://blog.csdn.net/qq_21126979/article/details/53672881。因为本章里面的代码是在上一篇文章的基础上修改的。
接下来我将会继续讲Service的更加高端的使用技巧,即AIDL 进程间的通信。
二、AIDL 基本介绍
aidl 是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。
创建AIDL的两种方式:Eclipse工具和Android studio工具
Android studio工具:
第一步:点击包名,右击->New->AIDL->AIDL File即可。
新建好的AIDL文件:
在IMyAidlInterface.aidl文件中编写相应的方法:
package com.hjyProject.aidl;interface IMyAidlInterface { //定义个获取详情方法 String getDetial(String name); //定义个set对象方法 void setObject(String obj);}
注意:如果aidl文件中出现编写格式不对,或者忘记导入引用包就不会生成一下的java文件。
第二步:生成相应的java文件:
生成java文件:
Eclipse 工具:
第一步:点击包名,右击->new->File
新建完文件后,编写以下程序,如下:
package com.hjyProject.util.aidl;import java.lang.Object;interface IMyAidlInterface { //定义个获取详情方法 String getDetial(String name); //定义个set对象方法 //void setObject(Object obj);}
编写好IMyAidlInterface文件后,如果语法还有格式没有出错的话,就会在gen文件下出现以下java文件:
我们将在两种工具下创建AIDL文件,接下去我将用AS工具进一步分析。
三、AIDL使用
接着上一篇的代码,在这里做几处修改。
1、在AndroidManifest.xml配置文件中写入以下代码:
<service android:name="com.hjyProject.service.TestService" android:process=":remote" > <!--隐式启动--> <intent-filter> <action android:name="com.hjyProject.aidl.IMyAidlInterface"/> </intent-filter></service>这边为什么使用隐式呢?
以下是上一篇文章中,bindService绑定服务的代码:
Intent intent = new Intent(ServiceActivity.this, TestService.class);bindService(intent,connection,BIND_AUTO_CREATE);看到bindService启动Intent我们就知道Intent使用TestService.class来指定要绑定哪一个Service的,但是在另一个应用程序中去绑定Service的时候并没有TestService这个类,这时就必须使用到隐式Intent了。所以只能做隐式跳转。
2、接下来修改TestService服务中的代码:
@Overridepublic IBinder onBind(Intent intent) { Log.d(TAG,"onBind"); //return new MyBinder(); return mStub;}private IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub(){ private String str; @Override public String getDetial(String name) throws RemoteException { Log.d(TAG,"getDetial"); return str+";"+name; } @Override public void setObject(String obj) throws RemoteException { Log.d(TAG,"setObject"); this.str = obj; }};
这里先是对MyAIDLService.Stub进行了实现,重写里了getDetial()和setObject ()这两个方法。这两个方法的作用分别是将塞字符串,另外一个是拼接字符串。然后在onBind()方法中将MyAIDLService.Stub的实现返回。这里为什么可以这样写呢?因为Stub其实就是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现。
3、最后我们修改ServiceActivity,代码如下:
private IMyAidlInterface myAIDLService;//Activity与Service建立关联与接触关联时候被调用private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { myAIDLService = IMyAidlInterface.Stub.asInterface(iBinder); try { myAIDLService.setObject("我"); String result = myAIDLService.getDetial("Hello!"); Log.d("test",result); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { }};/*** 界面初始化* @author hjy* created at 2016/12/15 13:46*/private void initUI(){ bind = (Button) findViewById(R.id.bind); //绑定服务 bind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Intent intent = new Intent(ServiceActivity.this, TestService.class); //BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service, // 这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。 Intent intent = new Intent("com.hjyProject.aidl.IMyAidlInterface"); bindService(intent,connection,BIND_AUTO_CREATE); } });}
我们只是修改了ServiceConnection中的代码。可以看到,这里首先使用了MyAIDLService.Stub.asInterface()方法将传入的IBinder对象传换成了MyAIDLService对象,接下来就可以调用在MyAIDLService.aidl文件中定义的所有接口了。在这里我setObject方法中传入“我”,getDetial方法中传入“Hello”,然后做字符串的拼接打印出来。结果如下:
java.lang.IllegalArgumentException: Service Intent must be explicit:
啊!为什么会出现这样的异常呢?后来我查找了资料,才知道Android5.0以后不支持隐式启动,那怎么办呢?我们只能用隐式。有一句话说的好,上有政策下有对策,google官方推荐使用的解决方法。
在此附上地址供大家参考:http://developer.android.com/goo ... tml#billing-service,有兴趣的可以去看看。
于是,我就引用了google官方推荐的方法,将隐式启动转换成显示。代码如下:
/** * 将隐式启动转换为显示启动 * @author hjy * created at 2016/12/16 14:07 */public static Intent getExplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent;}/*** 界面初始化* @author hjy* created at 2016/12/15 13:46*/private void initUI(){ bind = (Button) findViewById(R.id.bind); //绑定服务 bind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent mIntent = new Intent(); mIntent.setAction("com.hjyProject.aidl.IMyAidlInterface"); Intent eintent = new Intent(getExplicitIntent(ServiceActivity.this,mIntent)); //startService(eintent); bindService(eintent,connection,BIND_AUTO_CREATE); }});}
引入google官方的方法getExplicitIntent后,在修改一下bind点击事件的方法中调用,完美解决。打印出log。
虽然我们已经简单实现了不同进程之间数据传递,但是你有没有发现如果我想传递复杂的对象,怎么办呢?上面只能传java的基本数据类型、字符串、List或者Map等。接下来我们将解刨怎么去传递自定类。接下去我将会写一篇 AIDL 进程间的通信(二)来说明进程间传递自定义对象。
如果有出错或者需要改进的地方,欢迎指点或者交流。
0 0
- AIDL 进程间的通信(一)
- 进程与进程间的通信(一)——Aidl
- AIDL(进程间通信)
- Android 进程间通信AIDL讲解 一
- Android 的进程间通信 Binder——AIDL的入门使用(一)
- AIDL 进程间通信
- AIDL 进程间通信
- AIDL 进程间通信
- AIDL 进程间通信
- AIDL进程间通信
- AIDL:进程间通信
- AIDL进程间通信
- AIDL 进程间通信
- aidl 进程间通信
- AIDL进程间通信
- 进程间通信---AIDL
- AIDL进程间通信
- AIDL进程间通信
- 编程的乐趣
- Android开发-自定义View-AndroidStudio(三)扇形多级菜单
- Ubuntu 16.04安装 openssh-server问题
- iOS 过滤非法字符集
- 硅谷也疯狂 IT互联网进入中美跨境人才抢夺战时代
- AIDL 进程间的通信(一)
- 对单片机中时钟的理解
- CPU卡发卡总结
- 如何在win 下安装ipython notebook
- STL 源码剖析笔记之仿函数
- jquery中siblings的用法
- iOS设计模式—原型/外观
- PHPExcel Excel文件导入
- 欢迎您在新浪博客安家