最近又重新看了点IPC的相关知识,以前看过不少Binder的知识,看到c++层思路就很模糊了,回头再看也算是一种学习。
IPC全称为:interprocess communication内部进程间通信,官方地址:http://developer.android.com/intl/zh-cn/guide/components/aidl.html,网上对这一块介绍的资料也着实不少,入门的话还是推荐看老罗的。
鉴于以前也知识看看相关知识,从来也没动手去做过,于是就照着官方文档开始动手创建Demo, 在按照官方文档实现之后,我察觉到有一个需求,官方只是说客户端可以调用远程服务端,那么远程服务端想要调用客户端可不可以呢?
为了尽快实现需求,那我就先将服务启动在本地,也就是说与Service与Activity处于同一进程,进行测试。它的结果是可行的,相关代码如下:
Activity相关代码:
<span style="font-family:Microsoft YaHei;font-size:14px;">public class MainActivity extends ActionBarActivity implements ServiceConnection, IServiceConnect {public final static String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {...bindService(new Intent("com.example.aidl.RemoteService"), this, BIND_AUTO_CREATE);}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {
<span style="white-space:pre"> </span>Log.e(TAG, "MainActivity onServiceConnected " + name + " - " + service);if (service instanceof ServiceBinder) {ServiceBinder new_name = (ServiceBinder) service;// 获取服务的引用,使服务与Activity建立双向关系RemoteService service2 = new_name.getService();service2.setmServiceConnect(this);}}...@Overridepublic void callback() {// 这种模式只有在同一进程中的服务才可以被使用Log.e(TAG, "MainActivity 被服务端调用");}@Overrideprotected void onDestroy() {super.onDestroy();unbindService(this);}
}
</span>
Service相关代码:
<span style="font-family:Microsoft YaHei;font-size:14px;">public class RemoteService extends Service implements Runnable {public final static String TAG = "RemoteService";public IServiceConnect mServiceConnect;...@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "RemoteService onBind");return new ServiceBinder(this);//返回含有服务引用的内部类}public static class ServiceBinder extends Binder {private RemoteService service;public ServiceBinder(RemoteService service) {super();this.service = service;}public RemoteService getService() {return service;}}public void setmServiceConnect(IServiceConnect mServiceConnect) {this.mServiceConnect = mServiceConnect;new Handler().postDelayed(RemoteService.this, 3000);//当建立连接之后启动一个任务}@Overridepublic void run() {if (mServiceConnect != null) {mServiceConnect.callback();//调用Activity的相关方法,验证通信}}}
</span>
上述结果是可以在同一进程的Activity与Service间互相通信的,因为在onServiceConnected中回调的Binder对象则为刚刚Service返回的对象,在Activity中打印的Log如下:
那么跨进程间互相通信可不可以呢?
我们在Service的Manifest文件中给Service添加Process属性,属性值为:remote:
<span style="font-family:Microsoft YaHei;font-size:14px;"><serviceandroid:name="com.example.aidl.RemoteService"android:process=":remote" ><intent-filter><action android:name="com.example.aidl.RemoteService" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></service></span>
好了,这下启动服务之后,它就属于远程服务了,它与Activity不属于同一个进程,在Android中一个进程则是一个虚拟机。
如果我再按照刚才的方法进行测试,服务是启动了,但是Activity收到的Binder对象却是这样的:
这里是说,返回的组件名称为RemoteService,但是返回的Binder对象则为BinderProxy,这个BinderProxy则为RemoteService远程服务在本地的代理,熟悉AIDL的相关信息的人,肯定知道Proxy知道是什么。
那么我们在这里可不可以从Proxy对象中把远程的RemoteService对象拿到呢,我们看一下调试信息:
我们看到在Proxy中的并没有RemoteService的引用,嗯,因为IPC通信,是跨进程的,我们都是通过代理与服务打交道的,所以...
那么回到标题,说说远程服务与本地服务的特点与差异:
其实都是服务,提供的功能一致,只是一个在本地,一个在其它进程,所以,服务与客户端打交道的时候就有了不同,要谨慎对待。