如下资料摘录整理自老罗的Android之旅博客,是对老罗的博客关于Android底层原理的一个抽象的知识归纳总结(若有错误欢迎指出)(侵删):
http://blog.csdn.net/luoshengyang/article/details/8923485
http://blog.csdn.net/luoshengyang/article/details/12957169数据库
整理by Doingide
安装应用程序的时候,并不会把相应的Content Provider加载到内存中来,系统采起的是懒加载的机制,等到第一次要使用这个Content Provider的时候,系统才会把它加载到内存中来,下次再要使用这个Content Provider的时候,就能够直接返回
Android应用程序组件Content Provider在应用程序之间共享数据的原理
Content Provider组件在不一样应用程序之间传输数据是基于
匿名共享内存机制来实现的(在应用程序进程之间以匿名共享内存的方式来传输数据效率是很是高的,由于它们之间只须要传递一个文件描述符就能够了):
首先
在第三方应用程序这一侧,当它须要访问Content Provider中的数据时,它会在本进程中
建立一个CursorWindow对象,它在内部建立了一块匿名共享内存,同时,它实现了Parcel接口,所以它能够在进程间传输。接下来第三方应用程序
把这个CursorWindow对象(连同它内部的匿名共享内存文件描述符)经过Binder进程间调用传输到Content Provider这一侧。这个匿名共享内存文件描述符传输到Binder驱动程序的时候,Binder驱动程序就会在目标进程(即Content Provider所在的进程)中
建立另外一个匿名共享文件描述符,指向前面已经建立好的匿名共享内存,所以,就实现了在
两个进程中共享同一块匿名内存。
在
Content Provider这一侧,
利用在Binder驱动程序为它建立好的这个匿名共享内存文件描述符,在本进程中建立了一个CursorWindow对象。如今,Content Provider开始要从本地中从数据库中查询第三方应用程序想要获取的数据了。Content Provider首先会建立一个
SQLiteCursor对象,即SQLite数据库游标对象,它继承了AbstractWindowedCursor类,后者又继承了AbstractCursor类,而AbstractCursor类又实现了CrossProcessCursor和Cursor接口。其中,最重要的是在AbstractWindowedCursor类中,有一个成员变量mWindow,它的类型为CursorWindow,这个成员变量是经过AbstractWindowedCursor的子类SQLiteCursor的setWindow成员函数来设置的。这个SQLiteCursor对象设置好了父类AbstractWindowedCursor类的mWindow成员变量以后,它就具备传输数据的能力了,由于这个mWindow对象内部包含一块匿名共享内存。此外,这个SQLiteCursor对象的内部有两个成员变量,一个是SQLite数据库对象mDatabase,另一个是SQLite数据库查询对象mQuery。SQLite数据库查询对象mQuery的类型为SQLiteQuery,它继承了SQLiteProgram类,后者又继承了SQLiteClosable类。SQLiteProgram类表明一个数据库存查询计划,它的成员变量mCompiledSql包含了一个已经编译好的SQL查询语句,
SQLiteCursor对象就是利用这个编译好的SQL查询语句来得到数据的,可是它并非立刻就去获取数据的,而是等到须要时才去获取。
那么,要等到何时才会须要获取数据呢?通常来讲,若是第三方应用程序在请求Content Provider返回数据时,若是指定了要返回关于这些数据的元信息时,例如数据条目的数量,那么Content Provider在把这个SQLiteCursor对象返回给第三方应用程序以前,就会去获取数据,由于只有获取了数据以后,才知道数据条目的数量是多少。SQLiteCursor对象经过调用成员变量mQuery的fillWindow成员函数来把从SQLite数据库中查询获得的数据保存其父类AbstractWindowedCursor的成员变量mWindow中去,即保存到第三方应用程序建立的这块匿名共享内存中去。若是第三方应用程序在请求Content Provider返回数据时,没有指定要返回关于这些数据的元信息,那么,就要等到第三方应用程序首次调用这个从Content Provider处返回的SQLiteCursor对象的数据获取方法时,才会真正执行从数据库存中查询数据的操做,例如调用了SQLiteCursor对象的getCount或者moveToFirst成员函数时。这是一种数据懒加载机制,须要的时候才去加载,这样就提升了数据传输过程当中的效率。
上面说到,
Content Provider向第三方应用程序返回的数据其实是一个SQLiteCursor对象,那么,这个SQLiteCursor对象是如何传输到第三方应用程序的呢?由于它自己并非一个Binder对象,咱们须要对它进行适配一下。首先,Content Provider会根据这个SQLiteCursor对象来建立一个CursorToBulkCursorAdaptor适配器对象,这个适配器对象是一个Binder对象,所以,它能够在进程间传输,同时,它实现了IBulkCursor接口。Content Provider接着就经过Binder进程间通讯机制把这个CursorToBulkCursorAdaptor对象返回给第三方应用程序,第三方应用程序获得了这个CursorToBulkCursorAdaptor以后,再在本地建立一个BulkCursorToCursorAdaptor对象,这个BulkCursorToCursorAdaptor对象的继承结构和SQLiteCursor对象是同样的,不过,它没有设置父类AbstractWindowedCursor的mWindow成员变量,所以,它只能够经过它内部的CursorToBulkCursorAdaptor对象引用来访问匿名共享内存中的数据,即经过访问Content Provider这一侧的SQLiteCursor对象来访问共享数据。
Content Provider的共享数据更新通知机制:
ContentObserver类的成员变量mTransport是一个Binder对象,它是要传递给ContentService服务的,以便当ContentObserver所监控的数据发生变化时,ContentService服务能够经过这个Binder对象通知相应的ContentObserver它监控的数据发生变化了
Android应用程序组件Content Provider中的数据更新通知机制和Android系统中的广播(Broadcast)通知机制的实现思路是类似的。然而,Content Provider中的数据监控机制与Android系统中的广播机制又有三个主要的区别:
- 一是前者是经过URI来把通知的发送者和接收者关联在一块儿的,然后者是经过Intent来关联的
- 二是前者的通知注册中心是由ContentService服务来扮演的,然后者是由ActivityManagerService服务来扮演的
- 三是前者负责接收数据更新通知的类必需要继承ContentObserver类,然后者要继承BroadcastReceiver类。
之因此会有这些区别,是因为Content Proivder组件的数据共享功能自己就是创建在URI的基础之上的,所以专门针对URI来设计另一套通知机制会更实用和方便,而Android系统的广播机制是一种更加通用的事件通知机制,它的适用范围会更普遍一些。