原文:http://hkbarton.sacredfir.com/?p=93
在Android中窗体与窗体之间如何互相调用和交换数据?窗体(Activity)和后台的服务(Service)如何通信?基于Unix(Linux)的系统都有一个很优秀的传统,就是倡导非常轻便的进程间通信(IPC)机制;倡导进程通过IPC来互相协作;倡导功能单一,小巧而强壮的进程,而不是又大又复杂的“万金油”。同样,在Android中我们可以将我们的Activity和Service放在不同的进程中运行,我们可以在我们的Task 中加载其他进程的Activity,这些机制都鼓励我们“尽量利用已有的功能,利用IPC和包含这些已有功能的程序协作,来完成一个完整的应用”,例如在我们的程序中充分利用Google Map的相关窗体和服务。所有这些都建立在一套轻便好用的IPC机制上。
Android的组件和进程间通信都建立在一种基于称为Intent的消息基础之上。Intent就是一种消息,它包含了两个重要的内容:1. 消息的目的,即这个消息是发给哪个组件的?(消息的目的中不会包含“消息是发给哪个进程”这样的信息,这里Android有意淡化进程的概念,而只让我们关心组件,因为了解太多关于进程的具体信息会加大复杂度,而又如何做到进程间的消息传递呢?下文会说到一种Android中关于这点比较特别的设计方式,我认为是一种简捷有用又符合手机特点的设计);2. 消息所携带的数据内容,即需要传递给目标的数据。下面是一个简单的利用Intent来启动一个Service并向其传递数据的代码示例:
Intent serviceIntent = new Intent(context, svrMain.class);
serviceIntent.putExtra(“Network_Report”, networkStatus);
context.startService(serviceIntent);
上面的代码首先构造了一个Intent对象,并在构造的时候指定了这个Intent的目的地,即“svrMain.class”,表示这个Intent是要传递给一个类名叫svrMain的Service。然后向这个Intent中放入了一个数据,数据的key为“Network_Report”,value为一个叫networkStatus的int类型变量,用来指明当前网络的状态。最后我们使用系统提供的上下文API,将这个Intent传递给指定的Service。
Intent的消息目的地分为两种模式,一种是显式的,一种是隐式的。我们上面的例子中看到的就是一个显式消息的例子。显式消息直接指定消息目的地组件的类元信息,例如上面例子中svrMain就是我们写的一个类名为svrMain的Service,class操作符就是获取其类元信息。
这种模式的消息由于已经确切知道了消息目标的确切信息,所以只适用于同一进程内的不同组件之间通信,例如打开一个子窗体,和同一进程中的service通信等。对应的,
隐式消息就一般用于跨进程的通信了,隐式消息没有确定的消息目的地,除了数据外,隐式消息只是包含了一些用于表征消息特征的描述字段。而一些需要收到某种特定特征消息的某个程序中的某个组件,需要通过在其所在程序的AndroidMainifest.xml中注册一种被称为
intent-filter的消息特征筛选器,然后Android系统会按照一定的匹配规则来匹配发出的消息特征和所有拥有响应这种特征的intent-filter的组件(无论是同一进程内的组件还是不同程序中的组件),匹配到的组件就会接受到相应的消息。前面的描述多少有些拗口,我们举个实际的例子来说明,如果我们想开启一个子窗体(无论这个窗体来自同一进程还是不同进程),我们除了使用显式消息外,我们还可以使用隐式消息:
Intent openSomeDiagIntent = new Intent();
openSomeDiagIntent.setAction(“edwin.demo.fooActivity”);
this.startActivity(openSomeDiagIntent);
上面的隐式消息不包含具体的目的地,而是仅包含一个名位“Action”的特征字符串,Action就是上文所说的Intent特征的一种。从字面上来理解,可以理解为这个消息所代表的是完成某一个动作的含义,由action来标明动作的名字。所有能够处理这种动作的Activity都可以收到该消息。对应的,可能在同一个程序或者另外的某个程序的AndroidMainifest.xml中声明了下面这样的一个Activity:
<activity android:name=”.fooActivity”>
<intent-filter>
<action android:name=”edwin.demo.fooActivity” />
</intent-filter>
</activity>
那么这就表示这个Activity能够收到并处理action为“edwin.demo.fooActivity”的消息。所以上面的代码串起来的效果就是,打开了这个名为.fooActivity的窗口,无论这个窗口是在当前的进程中还是另外的一个程序中。
除了Action这种消息特征外,Intent还有category,data这两个特征描述属性。Category同样是一个字符串,从字面上理解就是“消息的分类特征”。从程序上看其和Action的不同在于,一个Intent只能有惟一的一个Action名称,但是却可以包含多个Category字符串;一个Intent-Filter可以包含多个Action节点但至少要包含一个,另一方面一个Intent-Filter可以包含零到多个Category节点。Android在做Intent-Filter匹配的时候,Intent的Action属性匹配到Intent-Filter中的任何一个action节点,就表明拥有这个Intent-Filter的组件能够处理这种消息;而对于Category来讲一个Intent中的所有的Category都必须存在于Intent-Filter中的Category节点中时,才表明匹配成功。Data属性可以描述一个Intent所要传递的数据类型和URI,每一个Intent只能包含一个Data属性。其中数据的类型使用MIME类型描述方式来描述,例如video/mpeg表示编码格式为mpeg的视频,这里也可以使用通配符,例如video/*表示任意格式的视频文件类型;数据的URI由scheme(协议),host,port,path四部分组成:scheme://host:port/path,例如http://test.com:8080/file/file1 或者content://edwin.demo.contentProvider:100/forder/content1,其中path部分也是可以支持通配符的。Data属性是一个很有用的描述特征,例如下面这样的一个包含data节点的Intent-Filter:
<activity android:name=”.actHttpVideoMan”>
<intent-filter>
<action android:name=”edwin.demo.actHttpVideoMan.Main” />
<data android:scheme=”http” android:type=”video/*” />
</intent-filter>
</activity>
它表示窗体actHttpVideoMan能够处理来自web服务器的视频文件。这样的filter有什么作用呢?最典型的情况就是配合浏览器工作。浏览器在打开一个链接的时候首先会尝试显示这个链接对应的html页面,如果这个链接不是一个html页面,而是一个视频文件或者其他浏览器本身不能处理的格式的话,浏览器会使用隐式消息尝试开启一个能够处理这种数据格式的Activity来处理,浏览器发出的隐式消息就是一个包含data属性,其中URI scheme为http,数据类型为video/*的消息,如果有能够匹配这个intent的组件,例如我们上面的那个activity,浏览器就会启动这个窗体,接着这个窗体会根据data属性指定的URI去播放在线视频,如果没有可以处理这个intent的Activity,浏览器才会调用下载管理器下载文件。
隐式消息这个设计简单有效,它忽略了进程的细节,让IPC在一个更高的更接近人脑思维模式的层次工作,让系统中的不同进程协作看起来就像是同一程序中的协作一样,这种简单的IPC机制在很大的程度上鼓励我们和其他进程协作,通过协作的进程来完成一个复杂的任务,而不是把什么功能都做到一个大而全的程序里面。不过上文还有一些细节没有提到,例如如果一个intent有多个可匹配的处理组件,系统如何处理?这就要分响应消息的组件类型来说了,如果是service,那么这些service都可以启动并处理消息,如果是Activity,则android会弹出一个对话框让用户进行选择。比如我们安装了多个可以处理在线视频的软件,当我们在浏览器中点击一个在线视频的链接时,系统会让用户选择使用哪个软件来观看。另外大家一定会想到安全性的问题,如果不同进程间的组件可以通过隐式消息互相通信,那我们的程序不是可以轻易调用到其他的程序或者系统中的一些敏感程序的组件,这样会不会很不安全呢?其实Android在安全方面有一个统一,完备和轻便的安全策略模型,Intent的安全自然是被考虑在内的,关于android的安全模型我会在后续的系列blog中专门说明。
最后,除了Intent这种基于消息的进程内和进程间通信模型外,android中也有一种相比起来稍显笨重一些的IPC机制,它采用类似远程方法调用的方案,通过接口定义文件AIDL来定义一个IPC接口,然后通过接收方实现接口,调用方调用接口的本地代理实现来完成IPC。这种模型只适用于Activity和Service间的通信,之所以需要这种稍显重量的模式,是因为Activity除了发送intent去启动一个service外,可能还需要能够在Service的运行过程中连接到service,对Service发送一些控制请求。例如音乐播放程序,其后台的播放服务往往独立运行,以方便我们在使用其他程序界面时也能听到音乐。同时这个后台播放服务也会定义一个控制接口,包含比如播放,暂停,快进之类的方法,任何时候播放程序的界面都可以通过使用bindService API连接到播放服务,获取这个接口的包含IPC细节的实现代理,通过这组控制接口方法对其进行控制,这时这种IPC的方案就显的更方便更直观一些了。有关使用AIDL这种IPC的更详细描述,Google的官方文档已做了详细的讲解。
分享到:
相关推荐
### Android开发手记一_NDK编程实例 #### 一、开发环境的搭建 在开始具体的NDK编程之前,首先需要确保开发环境已经被正确地搭建起来。对于初次接触Android NDK开发的朋友来说,拥有一个良好的环境配置是至关重要的...
总之,Android开发手记中的环境配置涵盖了从下载SDK、安装ADT插件到创建新项目、理解项目结构和XML布局文件的整个过程。掌握这些基础知识是成为合格Android开发者的第一步。在实际开发中,还需要学习更多的API、生命...
例如,当你在BrewClock项目中遇到计时器功能的问题,通过研究相关开源计时器的源码,你可以学习到如何实现精确的定时器机制,以及如何处理用户交互和UI更新。 其次,工具的运用是提高开发效率的重要手段。Android ...
首先,你需要安装Android Studio,这是Google官方提供的集成开发环境(IDE),它包含了所有必要的工具,如SDK Manager、AVD Manager等,用于下载和管理Android SDK组件,创建虚拟设备进行测试。安装完成后,启动一个...
Android 开发手记 -- 环境配置 Android 开发手记是基于 Linux 内核的手机系统,使用 MyEclipse + Windows XP 作为开发工具,当然在 Linux 下开发是更好的选择。以下是 Android 开发环境配置的步骤: 第一步:下载 ...
Android SDK(Software Development Kit)是Android应用程序开发的核心工具集,它包含了开发者创建、测试和调试Android应用所需的所有资源。SDK不仅包括了核心库文件,还包含了各种工具,如模拟器、调试工具等。 ##...
根据提供的标题“Oracle DBA手记3”及描述“Oracle DBA手记3,完整的,内容不错,大家可以下了”,我们可以推断出这份资料是关于Oracle数据库管理(DBA)的一系列经验分享和技术指南。虽然具体的内容没有给出,但是...
MATLAB GUI设计学习是计算机科学领域的一个重要分支,特别是在数据可视化、科学研究以及工程...通过深入研究这些源码,你可以更好地理解和运用MATLAB GUI设计的各个方面,从而创建出更符合用户需求的交互式应用程序。
3. 流畅度提升:流畅度关系到用户使用应用时的体验,特别是在滑动、动画等交互过程中。为了提升流畅度,开发者需要降低卡顿,优化界面绘制效率,使用如Android Profiler等工具检测UI线程的性能瓶颈,以及合理使用...
在研究和开发过程中,变速齿轮也有其独特的价值。开发者可以利用它快速测试长时间运行的代码段,找出性能瓶颈,或者在短时间内复现问题。此外,它也可以用于模拟不同的硬件性能,以测试软件在各种条件下的表现。 ...
此外,语音识别和语音合成作为AR应用中的重要交互方式,也在本手记中有所提及。语音识别可以通过百度的技术实现,而语音合成则涉及到将文字信息转换成语音输出。 性能参数方面,本手记提供了详细的数据,包括APK包...
非常摄影手记玩转单反相机,,2天玩转单反相机,电子工业出版社
3. **数据交互**:如何在GUI组件之间以及GUI与外部数据源之间传递和显示数据。 4. **布局管理**:如何使用不同的布局管理器优化界面布局。 5. **图形绘制**:如何在GUI中绘制2D和3D图形,包括静态图和动态图。 6. **...
接口技术是单片机应用中不可或缺的一部分,手记可能涉及串行通信(如UART、SPI、I2C)、并行接口、A/D和D/A转换、LCD显示、键盘扫描等。这些接口技术的学习能帮助读者实现单片机与外部设备的交互。 除此之外,...
### Bootstrap组件学习手记 #### 一、图标字体的使用 在Bootstrap中,图标字体的使用非常方便且直观。它们通常被嵌入到`<span>`标签中,并通过类名来调用不同的图标。作者提到在尝试使用这些图标时遇到了一些问题...
以下是对JMail组件各主要属性和方法的详细说明: 1. **Body**: 这个属性用于设置邮件的正文内容,可以是文本或HTML格式,例如`JMail.Body = "这里可以是用户填写的表单内容,可以取自 From。"`。 2. **Charset**: ...
MATLAB(Matrix Laboratory)是一种强大的交互式环境,用于数值计算、符号计算、数据可视化、图像处理和编程。GUI(Graphical User Interface)设计是MATLAB中的一个重要应用领域,它允许用户通过图形化界面与程序...
《从零开始玩转PIC之旋转时钟》是《匠人手记》系列中的一个章节,由程序匠人撰写,详细介绍了如何利用PIC单片机设计并制作一款旋转时钟。这一章节不仅提供了理论知识,还包含了实际的操作指南,对于初学者来说是一个...