IPC机制 续

来源:互联网 发布:township破解版无网络 编辑:程序博客网 时间:2024/06/17 13:29

接下来讲的是使用ContentProvider,它是安卓中提供的专门用于不同应用间进行数据共享的方式,这点来看它就天生适合进程间的通信,和messenger一样它的底层其实也是binder实现,但是它的使用过程要比aidl简单的多,因为安卓都为其封装好了。

下面介绍它的具体使用过程:

首先创建一个类继承ContentProvider类并实现6个必须需要实现的方法,也就是我们所说增删改查还有一个oncreate和getTpye方法。四大组件都需要注册的,因此我们需要在menifest文件里对contentprovider进行注册,其中android:authorities是它的唯一标识,为了演示进程间的通信,我们也可以加上process属性,和permission权限的声明。

注册好了我们就可以外部访问它了。我们在主activity中通过getContentResolver获取contentresolver去试着查询一下,访问contentprovider的query方法。它的第一个参数是uri也就是我们前面所说的authorities属性值,

Uri uri=Uri.parse("content://....").到这里整个contentprovider的流程也就跑通了,通过测试我们发现了,contentprovider里的什么增删改查方法都是运行在Binder线程中,只有oncreate是运行在main线程中,也就是UI线程,我们不能在oncreate方法里做耗时工作。


接下来在上面的基础上,我们继续完善,因为还没有数据,所以我们这里需要一个数据库来管理图书和用户(我们假设是这样的数据库)信息,其实数据库不难实现。

下面给大家介绍一下实现数据库的步骤:

首先写一个类继承SQLiteOpenHelper类,在里面定义好需要用到的常量,像数据库名表名和数据库版本号等等。还有定义好创建表的sql语句,这些就是一个最简单的数据库的实现,在平时不用contentprovider的时候,我们使用数据库相关的操作时还应写一个管理类,里面包括一些常见的增删改查等等的操作,在这个类里new一下之前写的类,然后.getWriteableDatabase()获取SQLiteDatabase,这个就是我们数据库各种数据库操作需要的。然后就db. ...等等各种操作。


这里的增删改查操作就都在contentprovider里实现了,这个时候需要考虑一个问题,就是我们刚刚创建数据库的时候创建了两个表,那么我们访问的时候怎么知道我们到底要访问哪个呢,所以这个时候我们就需要用到uri匹配器了。创建一个UriMatcher然后在静态代码块里进行添加uri的方法,三个参数,第一个是authority,第二个是path,它第一个就组成来一个完整的uri,然后就能区分要进行的操作是什么,第三个是code,就是匹配成功返回的code,这个在switch case操作就能根据返回码的不同来做相应的操作。注意里面的增删改查的操作时存在多线程并发访问的,因此方法内部要做好线程同步。现在讲的这个例子则不需要,因为只有一个sqlitedatabase的连接。。。

接下来就可以在activity里进行相关的操作了。


这里还有最后一个实现进程间的通信方法,就是使用socket,我们也称之为套接字,其实大家在学习java网络通信的时候,应该都学过。它分为流式套接字和数据报套接字,对应于网络传输控制层中的tcp和udp协议。tcp是面向连接的协议,提供稳定的双向通信功能,tcp连接的建立需要经过“三次握手”才能完成,为了提供稳定的数据传输功能,其本身提供了超时重传机制,因此具有很高的稳定性,而udp 是无连接的,提供不稳定的单向通信功能,当然也可以实现双向通信功能。在性能上,udp具有更好的效率,其缺点就是不能保证数据的正确传输,尤其是在网络拥塞的情况下。接下来演示一个跨进程聊天程序。两个进程可以通过socket实现信息的传输,很显然这是一种ipc方式。

使用socket来进行通信,有两点需要注意,首先是要声明权限,一个是网络权限,一个是android.permission.ACCESS_NETWORK_STATE.其次注意不能在主线程中访问网络。

服务端的设计:服务端没收到一个客户端的消息就会随机回复一句话给客户端。当客户端开链接时服务端也会关闭相应的socket并结束通话线程。

在oncreate方法里启动一个线程,随时接听来自客户端的信息,然后对其作出回复。

客户端:在客户端的oncreate方法开启一个线程去连接服务端socket。当activity退出时,就关闭当前的socket。


以上就是所有的跨进程通信的所有方法了,这些就是典型的使用流程,可是问题来了,公司的项目越来越大,有10个不同的业务模块都需要使用aidl来进行进程间通信,那么该怎么处理?我们当然不能创建10个service吧,那样我们的应用会看起来很重量级,这里就引入来Binder连接池的概念。

具体流程:

首先为binder连接池创建远程service并实现ibinderpool(aidl接口里面就有我们所需要的queryBinder(int bindercode)方法)。下面就是Binder连接池自己的实现了,里面有单例模式获取实例,有连接远程服务获取aidl接口的querybinder方法。

最后创建一个activity,在里面实现,先获取binder pool实例,在调用里面的query binder方法,获取需要的IBinder对象,然后在.asInterface方法,获取接口,最后调用里面的方法。

这里binderpool连接池就相当于在activity获取它的时候它就做了本应该activity做的工作,连接远程服务,和实现接口里面的方法。然后activity通过它来回去需要的接口,然后实现方法。很巧妙的一种想法。简便很多。因此建议大家以后在aidl开发工作中引入binderpool机制。



具体源码可联系我。

qq:434638973


下面来总结一下,我们到现在为止所讲的这些方法实现进程间通信的利弊。

bundle,简单易用,只能传输bundle支持的数据类型,适用四大组件间的进程通信

文件共享,不适合高并发场景,并且无法做到进程间的及时通信。适用于无并发的情形,交换简单的数据实时性不高的场景。

aidl,功能强大,支持一对多并发通信,支持实时通信,使用稍复杂,适用一对多通信,且有rpc要求就是需要调用远程的方法。

messenger,功能一般,支持一对多的串行通信,支持实时通信,不能很好的处理高并发情形,不支持rpc,数据通过message进行传输因此职能传输bundle支持的数据类型。

contentprovider,在数据元访问方面功能很强大,主要提供数据元crud操作,适用一对多的进程间的数据共享

socket,功能强大,可以通过网络传输字节流,支持一对多并发实时通信。实现细节稍微有点繁琐,适用网络数据交换


有问题可以彼此交流探讨


0 0
原创粉丝点击