由于android系统中应用程序之间不能共享内存,因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些。
在android SDK中提供了4种用于跨进程通讯的方式,这4种方式正好对应于android系统中4种应用程序组件:Activity、Content Provider、Broadcast和Service。
-
Activity可以跨进程调用其他应用程序的Activity;
-
Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操作;
-
Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;
-
Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
方式一:访问其他应用程序的Activity
Activity既可以在进程内(同一个应用程序)访问,也可以跨进程访问。如果想在同一个应用程序中访问Activity,需要指定Context对象和Activity的Class对象。
Activity的跨进程访问与进程内访问略有不同。虽然它们都需要Intent对象,但跨进程访问并不需要指定Context对象和Activity的Class对象,而需要指定的是要访问的Activity所对应的Action(一个字符串),有些Activity还需要指定一个Uri(通过Intent构造方法的第2个参数指定)。
try {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.dvb.dtv.home", "com.dvb.dtv.home.InitActivity"));
thisActivity.startActivity(intent);
} catch (Exception e) {
showToast(getResources().getString(R.string.main_app_open_error));
}
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" );
startActivity(callIntent);
下面先来看一下如何将应用程序的Activity共享出来,读者可按如下几步来共享Activity:
-
在AndroidManifest.xml文件中指定Action。指定Action要使用
<action>
标签,并在该标签的android:name属性中指定Action。 -
在AndroidManifest.xml文件中指定访问协议。在指定Uri(Intent类的第2个参数)时需要访问协议。访问协议需要使用
<data>
标签的android:scheme属性来指定。如果该属性的值是“abc”,那么Uri就应该是“abc://Uri的主体部分”,也就是说,访问协议是Uri的开头部分。 -
通过getIntent().getData().getHost()方法获得协议后的Uri的主体部分。这个Host只是个称谓,并不一定是主机名,可以将其看成是任意的字符串。
-
从Bundle对象中获得其他应用程序传递过来的数据。
-
获得数据后根据具体的需求做进一步的处理。
方式二:Content Provider
Android应用程序可以使用文件或SqlLite数据库来存储数据。ContentProvider提供了一种在多个应用程序之间数据共享的方式(跨进程共享数据)。应用程序可以利用Content Provider完成下面的工作
-
查询数据
-
修改数据
-
添加数据
-
删除数据
虽然Content Provider也可以在同一个应用程序中被访问,但这么做并没有什么意义。Content Provider存在的目的向其他应用程序共享数据和允许其他应用程序对数据进行增、删、改操作。
Android系统本身提供了很多Content Provider,例如音频、视频、联系人信息等等。我们可以通过这些Content Provider获得相关信息的列表。这些列表数据将以Cursor对象返回。因此,从Content Provider返回的数据是二维表的形式。
对于访问Content Provider的程序,需要使用ContentResolver对象。该对象需要使用getContentResolver方法获得,代码如下:
ContentResolver cr = getContentResolver();
与Activity一样,Content Provider也需要与一个URI对应。每一个Content Provider可以控制多个数据集,在这种情况下,每一个数据集会对应一个单独的URI,所有的URI必须以“content://”开头。
为了程序更容易维护,也为了简化程序代码,一般将URI定义成一个常量。例如,下面的常量表示系统的联系人电话号码。
android.provider.Contacts.Phones.CONTENT_URI
下面来看一下编写Content Provider的具体步骤。
-
编写一个继承于android.content.ContentProvider的子类。
该类是ContentProvider的核心类,在该类中会实现query、insert、update及delete方法。实际上调用ContentResolver类的这4个方法就是调用ContentProvider类中与之要对应的方法。也是通过Uri传递参数,然后在这些方法中接收这些参数,并做进一步地处理。
-
在AndroidManifest.xml文件中配置ContentProvider。
要想唯一确定一个ContentProvider,需要指定这个ContentProvider的URI,除此之外,还需要指定URI所对应的ContentProvider类。这有些像Servlet的定义,除了要指定Servlet对应的Web地址,还要指定这个地址所对应的Servlet类。
方式三:广播(Broadcast)
广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。
在应用程序中发送广播比较简单,只需要调用sendBroadcast方法即可。该方法需要一个Intent对象,通过Intent对象可以发送需要广播的数据。
方式四:Service -> Remote Service -> AIDL服务
服务(Service)是android系统中非常重要的组件,Service可以脱离应用程序运行。也就是说,应用程序只起到一个启动Service的作用。一但Service被启动,就算应用程序关闭,Service仍然会在后台运行。
android系统中的Service主要有两个作用:后台运行和跨进程通讯。
后台运行就不用说了,当Service启动后,就可以在Service对象中 运行相应的业务代码,而这一切用户并不会察觉。
如果想让应用程序可以跨进程通讯,就要使用我们这节讲的AIDL服务,AIDL的全称是Android Interface Definition Language,也就是说,AIDL实际上是一种接口定义语言。通过这种语言定义接口后,Eclipse插件(ODT)会自动生成相应的Java代码接 口代码。
下面来看一下编写一个AIDL服务的基本步骤。
-
在Eclipse工程的package目录中建立一个扩展名为aidl的文件,package目录就是Java类所在的目录。该文件的语法类似于Java代码,aidl文件中定义的是AIDL服务的接口,这个接口需要在调用AIDL服务的程序中访问。
-
如果aidl文件的内容是正确的,Eclipse插件会自动生成一个Java接口文件(*.java)。
-
建立一个服务类(Service的子类)。
-
实现由aidl文件生成的Java接口。
-
在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,标签的android:name属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。
在编写AIDL服务和客户端时要注意如下两点。
-
AIDL服务中的onBind方法必须返回AIDL接口对象,该对象也是onServiceConnected事件方法的第2个参数值。
-
bindService方法的第1个参数是Intent对象,该对象构造方法的参数需要指定AIDL服务的ID,也就是在 AndroidManifest.xml文件中标签的子标签的android:name属性 的值。
总结
本文介绍了4种跨进程通讯的方式:Activity、ContentProvider、Broadcast和AIDL Service。
-
其中Activity可以跨进程调用其他应用程序的Activity;
-
ContentProvider可以访问其他应用程序返回的Cursor对象;
-
Broadcast采用的是被动接收的方法,也就是说,客户端只能接收广播数据,而不能向发送广播的程序发送信息。
-
AIDL Service可以将程序中的某个接口公开,这样在其他的应用程序中就可以象访问本地对象一样访问AIDL服务对象了。
这4种跨进程通讯的方式可以应用在不同的场合,例如,在需要显示可视化的界面时可以用Activity,需要返回记录集时可以用ContentProvider。